From: David ‘Bombe’ Roden Date: Wed, 26 Jun 2019 18:11:21 +0000 (+0200) Subject: 🔀 Merge branch 'release-79' X-Git-Tag: v79^0 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=03cec6a6772c2d836d94864adddaf544cbe9d72f;hp=6f1f26e3998cfef155b0cf59152827accea70d30 🔀 Merge branch 'release-79' --- diff --git a/.builds/jdk-1.8.yml b/.builds/jdk-1.8.yml new file mode 100644 index 0000000..5edd26d --- /dev/null +++ b/.builds/jdk-1.8.yml @@ -0,0 +1,18 @@ +image: alpine/edge +packages: + - openjdk8 +sources: + - https://git.sr.ht/~bombe/sone +tasks: + - clean: | + cd sone + ./gradlew clean + - build: | + cd sone + ./gradlew build + - test: | + cd sone + ./gradlew test + - jar: | + cd sone + ./gradlew fatJar diff --git a/.gitignore b/.gitignore index 99b31c6..fce4db9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /target /src/generated + +/.gradle/ +/build/ diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..6775f35 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,39 @@ +pipeline { + agent any + + options { + timestamps() + } + + stages { + stage('Build') { + steps { + sh './gradlew clean classes testClasses' + } + } + stage('Test') { + steps { + sh './gradlew test' + } + post { + always { + junit 'build/test-results/test/*.xml' + } + } + } + stage('Binary') { + steps { + sh './gradlew fatJar' + archiveArtifacts artifacts: 'build/libs/sone*-jar-with-dependencies.jar', fingerprint: true + } + } + stage('Reports') { + steps { + sh './gradlew jacocoTestReport findbugsMain countLines' + jacoco classPattern: 'build/classes/*/main', sourcePattern: '**/src/main/' + findbugs canComputeNew: false, defaultEncoding: '', excludePattern: '', healthy: '', includePattern: '', pattern: '**/findbugs/main.xml', unHealthy: '' + sloccountPublish encoding: '', pattern: 'build/reports/cloc/*.xml' + } + } + } +} diff --git a/build.gradle b/build.gradle index 8111c2a..01832fb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,21 @@ group = 'net.pterodactylus' -version = '0.9.8' +version = '79' buildscript { - ext.kotlinVersion = '1.2.0' + ext.kotlinVersion = '1.2.71' repositories { mavenCentral() } dependencies { - classpath group: 'info.solidsoft.gradle.pitest', name: 'gradle-pitest-plugin', version: '1.1.11' + classpath group: 'info.solidsoft.gradle.pitest', name: 'gradle-pitest-plugin', version: '1.4.0' classpath group: 'org.jetbrains.kotlin', name: 'kotlin-gradle-plugin', version: kotlinVersion classpath group: 'org.jetbrains.kotlin', name: 'kotlin-noarg', version: kotlinVersion } } repositories { - maven { url "http://maven.pterodactylus.net/" } mavenCentral() + maven { url "https://maven.pterodactylus.net/" } } apply plugin: 'java' @@ -45,14 +45,14 @@ dependencies { compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib' compile group: 'net.pterodactylus', name: 'utils', version: '0.12.4' - compile group: 'com.google.inject', name: 'guice', version: '3.0' - compile group: 'com.google.guava', name: 'guava', version: '14.0.1' + compile group: 'com.google.inject', name: 'guice', version: '4.2.2' + compile group: 'com.google.guava', name: 'guava', version: '27.0.1-android' compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.1' compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.9.1' compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2' compile group: 'org.jsoup', name: 'jsoup', version: '1.10.2' - testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-test' + testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-test-junit' testCompile group: 'junit', name: 'junit', version: '4.11' testCompile group: 'org.mockito', name: 'mockito-core', version: '2.10.0' testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3' @@ -60,8 +60,12 @@ dependencies { apply from: 'version.gradle' +test { + maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 +} + task fatJar(type: Jar) { - archiveName = project.name + '-jar-with-dependencies.jar' + archiveName = project.name.toLowerCase() + '-jar-with-dependencies.jar' from { (configurations.runtime - configurations.provided).collect { it.isDirectory() ? it : zipTree(it) } } manifest { attributes('Plugin-Main-Class': 'net.pterodactylus.sone.main.SonePlugin') diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92781d4..c19a936 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-all.zip diff --git a/settings.gradle b/settings.gradle index e60d974..97902dc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'sone' +rootProject.name = 'Sone' diff --git a/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java b/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java index 37e0ed5..99c1c9d 100644 --- a/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java +++ b/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java @@ -27,17 +27,15 @@ import net.pterodactylus.util.config.Configuration; /** * Parses a {@link Sone}’s data from a {@link Configuration}. - * - * @author David ‘Bombe’ Roden */ public class ConfigurationSoneParser { private final Configuration configuration; private final Sone sone; private final String sonePrefix; - private final Map albums = new HashMap(); - private final List topLevelAlbums = new ArrayList(); - private final Map images = new HashMap(); + private final Map albums = new HashMap<>(); + private final List topLevelAlbums = new ArrayList<>(); + private final Map images = new HashMap<>(); public ConfigurationSoneParser(Configuration configuration, Sone sone) { this.configuration = configuration; @@ -86,7 +84,7 @@ public class ConfigurationSoneParser { public Set parsePosts(PostBuilderFactory postBuilderFactory) throws InvalidPostFound { - Set posts = new HashSet(); + Set posts = new HashSet<>(); while (true) { String postPrefix = "/Posts/" + posts.size(); String postId = getString(postPrefix + "/ID", null); @@ -123,7 +121,7 @@ public class ConfigurationSoneParser { public Set parsePostReplies( PostReplyBuilderFactory postReplyBuilderFactory) { - Set replies = new HashSet(); + Set replies = new HashSet<>(); while (true) { String replyPrefix = "/Replies/" + replies.size(); String replyId = getString(replyPrefix + "/ID", null); @@ -149,7 +147,7 @@ public class ConfigurationSoneParser { } public Set parseLikedPostIds() { - Set likedPostIds = new HashSet(); + Set likedPostIds = new HashSet<>(); while (true) { String likedPostId = getString("/Likes/Post/" + likedPostIds.size() + "/ID", @@ -163,7 +161,7 @@ public class ConfigurationSoneParser { } public Set parseLikedPostReplyIds() { - Set likedPostReplyIds = new HashSet(); + Set likedPostReplyIds = new HashSet<>(); while (true) { String likedReplyId = getString( "/Likes/Reply/" + likedPostReplyIds.size() + "/ID", null); @@ -176,7 +174,7 @@ public class ConfigurationSoneParser { } public Set parseFriends() { - Set friends = new HashSet(); + Set friends = new HashSet<>(); while (true) { String friendId = getString("/Friends/" + friends.size() + "/ID", null); diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 7384eda..b0df7a9 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -1,5 +1,5 @@ /* - * Sone - Core.java - Copyright © 2010–2016 David Roden + * Sone - Core.java - Copyright © 2010–2019 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 @@ -48,8 +48,6 @@ import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound; import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound; -import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent; import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; import net.pterodactylus.sone.core.event.MarkPostKnownEvent; @@ -113,8 +111,6 @@ import kotlin.jvm.functions.Function1; /** * The Sone core. - * - * @author David ‘Bombe’ Roden */ @Singleton public class Core extends AbstractService implements SoneProvider, PostProvider, PostReplyProvider { @@ -158,23 +154,20 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, /** The trust updater. */ private final WebOfTrustUpdater webOfTrustUpdater; - /** The times Sones were followed. */ - private final Map soneFollowingTimes = new HashMap(); - /** Locked local Sones. */ /* synchronize on itself. */ - private final Set lockedSones = new HashSet(); + private final Set lockedSones = new HashSet<>(); /** Sone inserters. */ /* synchronize access on this on sones. */ - private final Map soneInserters = new HashMap(); + private final Map soneInserters = new HashMap<>(); /** Sone rescuers. */ /* synchronize access on this on sones. */ - private final Map soneRescuers = new HashMap(); + private final Map soneRescuers = new HashMap<>(); /** All known Sones. */ - private final Set knownSones = new HashSet(); + private final Set knownSones = new HashSet<>(); /** The post database. */ private final Database database; @@ -183,7 +176,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, private final Multimap trustedIdentities = Multimaps.synchronizedSetMultimap(HashMultimap.create()); /** All temporary images. */ - private final Map temporaryImages = new HashMap(); + private final Map temporaryImages = new HashMap<>(); /** Ticker for threads that mark own elements as known. */ private final ScheduledExecutorService localElementTicker = Executors.newScheduledThreadPool(1); @@ -208,22 +201,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * The database */ @Inject - public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, UpdateChecker updateChecker, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) { - super("Sone Core"); - this.configuration = configuration; - this.freenetInterface = freenetInterface; - this.identityManager = identityManager; - this.soneDownloader = new SoneDownloaderImpl(this, freenetInterface); - this.imageInserter = new ImageInserter(freenetInterface, freenetInterface.new InsertTokenSupplier()); - this.updateChecker = updateChecker; - this.webOfTrustUpdater = webOfTrustUpdater; - this.eventBus = eventBus; - this.database = database; - preferences = new Preferences(eventBus); - } - - @VisibleForTesting - protected Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, SoneDownloader soneDownloader, ImageInserter imageInserter, UpdateChecker updateChecker, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) { + public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, SoneDownloader soneDownloader, ImageInserter imageInserter, UpdateChecker updateChecker, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) { super("Sone Core"); this.configuration = configuration; this.freenetInterface = freenetInterface; @@ -401,20 +379,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } /** - * Returns the time when the given was first followed by any local Sone. - * - * @param sone - * The Sone to get the time for - * @return The time (in milliseconds since Jan 1, 1970) the Sone has first - * been followed, or {@link Long#MAX_VALUE} - */ - public long getSoneFollowingTime(Sone sone) { - synchronized (soneFollowingTimes) { - return Optional.fromNullable(soneFollowingTimes.get(sone.getId())).or(Long.MAX_VALUE); - } - } - - /** * Returns a post builder. * * @return A new post builder @@ -480,7 +444,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * @return The Sones that like the given post */ public Set getLikes(Post post) { - Set sones = new HashSet(); + Set sones = new HashSet<>(); for (Sone sone : getSones()) { if (sone.getLikedPostIds().contains(post.getId())) { sones.add(sone); @@ -497,7 +461,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * @return The Sones that like the given reply */ public Set getLikes(PostReply reply) { - Set sones = new HashSet(); + Set sones = new HashSet<>(); for (Sone sone : getSones()) { if (sone.getLikedReplyIds().contains(reply.getId())) { sones.add(sone); @@ -723,7 +687,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } database.storeSone(sone); soneDownloader.addSone(sone); - soneDownloaders.execute(soneDownloader.fetchSoneWithUriAction(sone)); + soneDownloaders.execute(soneDownloader.fetchSoneAsUskAction(sone)); return sone; } @@ -739,24 +703,20 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, checkNotNull(sone, "sone must not be null"); checkNotNull(soneId, "soneId must not be null"); database.addFriend(sone, soneId); - synchronized (soneFollowingTimes) { - if (!soneFollowingTimes.containsKey(soneId)) { - long now = System.currentTimeMillis(); - soneFollowingTimes.put(soneId, now); - Sone followedSone = getSone(soneId); - if (followedSone == null) { - return; - } - for (Post post : followedSone.getPosts()) { - if (post.getTime() < now) { - markPostKnown(post); - } - } - for (PostReply reply : followedSone.getReplies()) { - if (reply.getTime() < now) { - markReplyKnown(reply); - } - } + @SuppressWarnings("ConstantConditions") // we just followed, this can’t be null. + long now = database.getFollowingTime(soneId); + Sone followedSone = getSone(soneId); + if (followedSone == null) { + return; + } + for (Post post : followedSone.getPosts()) { + if (post.getTime() < now) { + markPostKnown(post); + } + } + for (PostReply reply : followedSone.getReplies()) { + if (reply.getTime() < now) { + markReplyKnown(reply); } } touchConfiguration(); @@ -774,15 +734,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, checkNotNull(sone, "sone must not be null"); checkNotNull(soneId, "soneId must not be null"); database.removeFriend(sone, soneId); - boolean unfollowedSoneStillFollowed = false; - for (Sone localSone : getLocalSones()) { - unfollowedSoneStillFollowed |= localSone.hasFriend(soneId); - } - if (!unfollowedSoneStillFollowed) { - synchronized (soneFollowingTimes) { - soneFollowingTimes.remove(soneId); - } - } touchConfiguration(); } @@ -898,44 +849,33 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } } - private List collectEventsForChangesInSone(Sone oldSone, - final Sone newSone) { - final List events = new ArrayList(); - SoneChangeDetector soneChangeDetector = new SoneChangeDetector( - oldSone); - soneChangeDetector.onNewPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - if (post.getTime() < getSoneFollowingTime(newSone)) { - post.setKnown(true); - } else if (!post.isKnown()) { - events.add(new NewPostFoundEvent(post)); - } - } - }); - soneChangeDetector.onRemovedPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - events.add(new PostRemovedEvent(post)); + private List collectEventsForChangesInSone(Sone oldSone, Sone newSone) { + List events = new ArrayList<>(); + SoneComparison soneComparison = new SoneComparison(oldSone, newSone); + for (Post newPost : soneComparison.getNewPosts()) { + if (newPost.getSone().equals(newSone)) { + newPost.setKnown(true); + } else if (newPost.getTime() < database.getFollowingTime(newSone.getId())) { + newPost.setKnown(true); + } else if (!newPost.isKnown()) { + events.add(new NewPostFoundEvent(newPost)); } - }); - soneChangeDetector.onNewPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - if (postReply.getTime() < getSoneFollowingTime(newSone)) { - postReply.setKnown(true); - } else if (!postReply.isKnown()) { - events.add(new NewPostReplyFoundEvent(postReply)); - } - } - }); - soneChangeDetector.onRemovedPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - events.add(new PostReplyRemovedEvent(postReply)); + } + for (Post post : soneComparison.getRemovedPosts()) { + events.add(new PostRemovedEvent(post)); + } + for (PostReply postReply : soneComparison.getNewPostReplies()) { + if (postReply.getSone().equals(newSone)) { + postReply.setKnown(true); + } else if (postReply.getTime() < database.getFollowingTime(newSone.getId())) { + postReply.setKnown(true); + } else if (!postReply.isKnown()) { + events.add(new NewPostReplyFoundEvent(postReply)); } - }); - soneChangeDetector.detectChanges(newSone); + } + for (PostReply postReply : soneComparison.getRemovedPostReplies()) { + events.add(new PostReplyRemovedEvent(postReply)); + } return events; } @@ -1388,7 +1328,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, identityManager.start(); webOfTrustUpdater.init(); webOfTrustUpdater.start(); - database.start(); + database.startAsync(); } /** @@ -1428,7 +1368,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } } saveConfiguration(); - database.stop(); + database.stopAsync(); webOfTrustUpdater.stop(); updateChecker.stop(); soneDownloader.stop(); @@ -1596,17 +1536,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, configuration.getStringValue("KnownSone/" + soneCounter + "/ID").setValue(null); } - /* save Sone following times. */ - soneCounter = 0; - synchronized (soneFollowingTimes) { - for (Entry soneFollowingTime : soneFollowingTimes.entrySet()) { - configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey()); - configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue()); - ++soneCounter; - } - configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(null); - } - /* save known posts. */ database.save(); @@ -1641,20 +1570,6 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, knownSones.add(knownSoneId); } } - - /* load Sone following times. */ - soneCounter = 0; - while (true) { - String soneId = configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").getValue(null); - if (soneId == null) { - break; - } - long time = configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").getValue(Long.MAX_VALUE); - synchronized (soneFollowingTimes) { - soneFollowingTimes.put(soneId, time); - } - ++soneCounter; - } } /** @@ -1720,7 +1635,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } } soneDownloader.addSone(sone); - soneDownloaders.execute(soneDownloader.fetchSoneAction(sone)); + soneDownloaders.execute(soneDownloader.fetchSoneAsSskAction(sone)); } /** diff --git a/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java b/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java index 946371b..1ed2024 100644 --- a/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java +++ b/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java @@ -1,5 +1,5 @@ /* - * Sone - FreenetInterface.java - Copyright © 2010–2016 David Roden + * Sone - FreenetInterface.java - Copyright © 2010–2019 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 @@ -32,6 +32,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; +import javax.inject.Inject; import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent; import net.pterodactylus.sone.core.event.ImageInsertFailedEvent; @@ -43,7 +44,6 @@ import net.pterodactylus.sone.data.TemporaryImage; import com.google.common.base.Function; import com.google.common.eventbus.EventBus; -import com.google.inject.Inject; import com.google.inject.Singleton; import freenet.client.ClientMetadata; @@ -78,8 +78,6 @@ import freenet.support.io.ResumeFailedException; /** * Contains all necessary functionality for interacting with the Freenet node. - * - * @author David ‘Bombe’ Roden */ @Singleton public class FreenetInterface { @@ -95,9 +93,10 @@ public class FreenetInterface { /** The high-level client to use for requests. */ private final HighLevelSimpleClient client; + private final RequestClient requestClient = new RequestClientBuilder().realTime().build(); /** The USK callbacks. */ - private final Map soneUskCallbacks = new HashMap(); + private final Map soneUskCallbacks = new HashMap<>(); /** The not-Sone-related USK callbacks. */ private final Map uriUskCallbacks = Collections.synchronizedMap(new HashMap()); @@ -258,7 +257,7 @@ public class FreenetInterface { try { soneUskCallbacks.put(routingKey(requestUri), uskCallback); node.clientCore.uskManager.subscribe(create(requestUri), - uskCallback, true, (RequestClient) client); + uskCallback, true, requestClient); } catch (MalformedURLException mue1) { logger.log(WARNING, format("Could not subscribe USK “%s”!", requestUri), mue1); @@ -271,8 +270,7 @@ public class FreenetInterface { soneUskCallbacks.put(routingKey(requestUri), uskCallback); node.clientCore .uskManager - .subscribe(create(requestUri), uskCallback, false, - (RequestClient) client); + .subscribe(create(requestUri), uskCallback, false, requestClient); } catch (MalformedURLException mue1) { logger.log(WARNING, format("Could not subscribe USK “%s”!", requestUri), @@ -328,7 +326,7 @@ public class FreenetInterface { }; try { - node.clientCore.uskManager.subscribe(USK.create(uri), uskCallback, true, (RequestClient) client); + node.clientCore.uskManager.subscribe(USK.create(uri), uskCallback, true, requestClient); uriUskCallbacks.put(uri, uskCallback); } catch (MalformedURLException mue1) { logger.log(Level.WARNING, String.format("Could not subscribe to USK: %s", uri), mue1); @@ -355,59 +353,7 @@ public class FreenetInterface { } /** - * Container for a fetched URI and the {@link FetchResult}. - * - * @author David Roden - */ - public static class Fetched { - - /** The fetched URI. */ - private final FreenetURI freenetUri; - - /** The fetch result. */ - private final FetchResult fetchResult; - - /** - * Creates a new fetched URI. - * - * @param freenetUri - * The URI that was fetched - * @param fetchResult - * The fetch result - */ - public Fetched(FreenetURI freenetUri, FetchResult fetchResult) { - this.freenetUri = freenetUri; - this.fetchResult = fetchResult; - } - - // - // ACCESSORS - // - - /** - * Returns the fetched URI. - * - * @return The fetched URI - */ - public FreenetURI getFreenetUri() { - return freenetUri; - } - - /** - * Returns the fetch result. - * - * @return The fetch result - */ - public FetchResult getFetchResult() { - return fetchResult; - } - - } - - /** * Callback for USK watcher events. - * - * @author David ‘Bombe’ Roden */ public static interface Callback { @@ -435,7 +381,6 @@ public class FreenetInterface { * @see ImageInsertStartedEvent * @see ImageInsertFailedEvent * @see ImageInsertFinishedEvent - * @author David ‘Bombe’ Roden */ public class InsertToken implements ClientPutCallback { @@ -558,11 +503,18 @@ public class FreenetInterface { } - public class InsertTokenSupplier implements Function { + public static class InsertTokenSupplier implements Function { + + private final FreenetInterface freenetInterface; + + @Inject + public InsertTokenSupplier(FreenetInterface freenetInterface) { + this.freenetInterface = freenetInterface; + } @Override public InsertToken apply(Image image) { - return new InsertToken(image); + return freenetInterface.new InsertToken(image); } } diff --git a/src/main/java/net/pterodactylus/sone/core/ImageInserter.java b/src/main/java/net/pterodactylus/sone/core/ImageInserter.java index f47b713..fc76ca9 100644 --- a/src/main/java/net/pterodactylus/sone/core/ImageInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/ImageInserter.java @@ -1,5 +1,5 @@ /* - * Sone - ImageInserter.java - Copyright © 2011–2016 David Roden + * Sone - ImageInserter.java - Copyright © 2011–2019 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 @@ -27,7 +27,10 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import javax.inject.Inject; + import net.pterodactylus.sone.core.FreenetInterface.InsertToken; +import net.pterodactylus.sone.core.FreenetInterface.InsertTokenSupplier; import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.TemporaryImage; @@ -38,8 +41,6 @@ import com.google.common.base.Function; * {@link FreenetInterface#insertImage(TemporaryImage, Image, InsertToken)} and * also tracks running inserts, giving the possibility to abort a running * insert. - * - * @author David ‘Bombe’ Roden */ public class ImageInserter { @@ -61,7 +62,8 @@ public class ImageInserter { * @param insertTokenSupplier * The supplier for insert tokens */ - public ImageInserter(FreenetInterface freenetInterface, Function insertTokenSupplier) { + @Inject + public ImageInserter(FreenetInterface freenetInterface, InsertTokenSupplier insertTokenSupplier) { this.freenetInterface = freenetInterface; this.insertTokenSupplier = insertTokenSupplier; } diff --git a/src/main/java/net/pterodactylus/sone/core/Options.java b/src/main/java/net/pterodactylus/sone/core/Options.java index 39b7b37..af88dd8 100644 --- a/src/main/java/net/pterodactylus/sone/core/Options.java +++ b/src/main/java/net/pterodactylus/sone/core/Options.java @@ -1,5 +1,5 @@ /* - * Sone - Options.java - Copyright © 2010–2016 David Roden + * Sone - Options.java - Copyright © 2010–2019 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 @@ -27,8 +27,6 @@ import com.google.common.base.Predicate; /** * Stores various options that influence Sone’s behaviour. - * - * @author David ‘Bombe’ Roden */ public class Options { diff --git a/src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt b/src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt new file mode 100644 index 0000000..2ebb62d --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/core/PreferenceChangedEvent.kt @@ -0,0 +1,3 @@ +package net.pterodactylus.sone.core + +data class PreferenceChangedEvent(val preferenceName: String, val newValue: Any) diff --git a/src/main/java/net/pterodactylus/sone/core/Preferences.java b/src/main/java/net/pterodactylus/sone/core/Preferences.java deleted file mode 100644 index 456e7f2..0000000 --- a/src/main/java/net/pterodactylus/sone/core/Preferences.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Sone - Preferences.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.core; - -import static com.google.common.base.Predicates.equalTo; -import static java.lang.Integer.MAX_VALUE; -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS; -import static net.pterodactylus.sone.utils.IntegerRangePredicate.range; - -import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; -import net.pterodactylus.sone.fcp.FcpInterface; -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; -import net.pterodactylus.sone.fcp.event.FcpInterfaceActivatedEvent; -import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent; -import net.pterodactylus.sone.fcp.event.FullAccessRequiredChanged; -import net.pterodactylus.sone.utils.DefaultOption; -import net.pterodactylus.sone.utils.Option; -import net.pterodactylus.util.config.Configuration; -import net.pterodactylus.util.config.ConfigurationException; - -import com.google.common.base.Predicates; -import com.google.common.eventbus.EventBus; - -/** - * Convenience interface for external classes that want to access the core’s - * configuration. - * - * @author David ‘Bombe’ Roden - */ -public class Preferences { - - private final EventBus eventBus; - private final Option insertionDelay = - new DefaultOption(60, range(0, MAX_VALUE)); - private final Option postsPerPage = - new DefaultOption(10, range(1, MAX_VALUE)); - private final Option imagesPerPage = - new DefaultOption(9, range(1, MAX_VALUE)); - private final Option charactersPerPost = - new DefaultOption(400, Predicates.or( - range(50, MAX_VALUE), equalTo(-1))); - private final Option postCutOffLength = - new DefaultOption(200, range(50, MAX_VALUE)); - private final Option requireFullAccess = - new DefaultOption(false); - private final Option positiveTrust = - new DefaultOption(75, range(0, 100)); - private final Option negativeTrust = - new DefaultOption(-25, range(-100, 100)); - private final Option trustComment = - new DefaultOption("Set from Sone Web Interface"); - private final Option activateFcpInterface = - new DefaultOption(false); - private final Option fcpFullAccessRequired = - new DefaultOption(ALWAYS); - - public Preferences(EventBus eventBus) { - this.eventBus = eventBus; - } - - /** - * Returns the insertion delay. - * - * @return The insertion delay - */ - public int getInsertionDelay() { - return insertionDelay.get(); - } - - /** - * Validates the given insertion delay. - * - * @param insertionDelay - * The insertion delay to validate - * @return {@code true} if the given insertion delay was valid, - * {@code false} otherwise - */ - public boolean validateInsertionDelay(Integer insertionDelay) { - return this.insertionDelay.validate(insertionDelay); - } - - /** - * Sets the insertion delay - * - * @param insertionDelay - * The new insertion delay, or {@code null} to restore it to - * the default value - * @return This preferences - */ - public Preferences setInsertionDelay(Integer insertionDelay) { - this.insertionDelay.set(insertionDelay); - eventBus.post(new InsertionDelayChangedEvent(getInsertionDelay())); - return this; - } - - /** - * Returns the number of posts to show per page. - * - * @return The number of posts to show per page - */ - public int getPostsPerPage() { - return postsPerPage.get(); - } - - /** - * Validates the number of posts per page. - * - * @param postsPerPage - * The number of posts per page - * @return {@code true} if the number of posts per page was valid, - * {@code false} otherwise - */ - public boolean validatePostsPerPage(Integer postsPerPage) { - return this.postsPerPage.validate(postsPerPage); - } - - /** - * Sets the number of posts to show per page. - * - * @param postsPerPage - * The number of posts to show per page - * @return This preferences object - */ - public Preferences setPostsPerPage(Integer postsPerPage) { - this.postsPerPage.set(postsPerPage); - return this; - } - - /** - * Returns the number of images to show per page. - * - * @return The number of images to show per page - */ - public int getImagesPerPage() { - return imagesPerPage.get(); - } - - /** - * Validates the number of images per page. - * - * @param imagesPerPage - * The number of images per page - * @return {@code true} if the number of images per page was valid, - * {@code false} otherwise - */ - public boolean validateImagesPerPage(Integer imagesPerPage) { - return this.imagesPerPage.validate(imagesPerPage); - } - - /** - * Sets the number of images per page. - * - * @param imagesPerPage - * The number of images per page - * @return This preferences object - */ - public Preferences setImagesPerPage(Integer imagesPerPage) { - this.imagesPerPage.set(imagesPerPage); - return this; - } - - /** - * Returns the number of characters per post, or -1 if the - * posts should not be cut off. - * - * @return The numbers of characters per post - */ - public int getCharactersPerPost() { - return charactersPerPost.get(); - } - - /** - * Validates the number of characters per post. - * - * @param charactersPerPost - * The number of characters per post - * @return {@code true} if the number of characters per post was valid, - * {@code false} otherwise - */ - public boolean validateCharactersPerPost(Integer charactersPerPost) { - return this.charactersPerPost.validate(charactersPerPost); - } - - /** - * Sets the number of characters per post. - * - * @param charactersPerPost - * The number of characters per post, or -1 to - * not cut off the posts - * @return This preferences objects - */ - public Preferences setCharactersPerPost(Integer charactersPerPost) { - this.charactersPerPost.set(charactersPerPost); - return this; - } - - /** - * Returns the number of characters the shortened post should have. - * - * @return The number of characters of the snippet - */ - public int getPostCutOffLength() { - return postCutOffLength.get(); - } - - /** - * Validates the number of characters after which to cut off the post. - * - * @param postCutOffLength - * The number of characters of the snippet - * @return {@code true} if the number of characters of the snippet is - * valid, {@code false} otherwise - */ - public boolean validatePostCutOffLength(Integer postCutOffLength) { - return this.postCutOffLength.validate(postCutOffLength); - } - - /** - * Sets the number of characters the shortened post should have. - * - * @param postCutOffLength - * The number of characters of the snippet - * @return This preferences - */ - public Preferences setPostCutOffLength(Integer postCutOffLength) { - this.postCutOffLength.set(postCutOffLength); - return this; - } - - /** - * Returns whether Sone requires full access to be even visible. - * - * @return {@code true} if Sone requires full access, {@code false} - * otherwise - */ - public boolean isRequireFullAccess() { - return requireFullAccess.get(); - } - - /** - * Sets whether Sone requires full access to be even visible. - * - * @param requireFullAccess - * {@code true} if Sone requires full access, {@code false} - * otherwise - */ - public void setRequireFullAccess(Boolean requireFullAccess) { - this.requireFullAccess.set(requireFullAccess); - } - - /** - * Returns the positive trust. - * - * @return The positive trust - */ - public int getPositiveTrust() { - return positiveTrust.get(); - } - - /** - * Validates the positive trust. - * - * @param positiveTrust - * The positive trust to validate - * @return {@code true} if the positive trust was valid, {@code false} - * otherwise - */ - public boolean validatePositiveTrust(Integer positiveTrust) { - return this.positiveTrust.validate(positiveTrust); - } - - /** - * Sets the positive trust. - * - * @param positiveTrust - * The new positive trust, or {@code null} to restore it to - * the default vlaue - * @return This preferences - */ - public Preferences setPositiveTrust(Integer positiveTrust) { - this.positiveTrust.set(positiveTrust); - return this; - } - - /** - * Returns the negative trust. - * - * @return The negative trust - */ - public int getNegativeTrust() { - return negativeTrust.get(); - } - - /** - * Validates the negative trust. - * - * @param negativeTrust - * The negative trust to validate - * @return {@code true} if the negative trust was valid, {@code false} - * otherwise - */ - public boolean validateNegativeTrust(Integer negativeTrust) { - return this.negativeTrust.validate(negativeTrust); - } - - /** - * Sets the negative trust. - * - * @param negativeTrust - * The negative trust, or {@code null} to restore it to the - * default value - * @return The preferences - */ - public Preferences setNegativeTrust(Integer negativeTrust) { - this.negativeTrust.set(negativeTrust); - return this; - } - - /** - * Returns the trust comment. This is the comment that is set in the web - * of trust when a trust value is assigned to an identity. - * - * @return The trust comment - */ - public String getTrustComment() { - return trustComment.get(); - } - - /** - * Sets the trust comment. - * - * @param trustComment - * The trust comment, or {@code null} to restore it to the - * default value - * @return This preferences - */ - public Preferences setTrustComment(String trustComment) { - this.trustComment.set(trustComment); - return this; - } - - /** - * Returns whether the {@link FcpInterface FCP interface} is currently - * active. - * - * @see FcpInterface#setActive(boolean) - * @return {@code true} if the FCP interface is currently active, - * {@code false} otherwise - */ - public boolean isFcpInterfaceActive() { - return activateFcpInterface.get(); - } - - /** - * Sets whether the {@link FcpInterface FCP interface} is currently - * active. - * - * @see FcpInterface#setActive(boolean) - * @param fcpInterfaceActive - * {@code true} to activate the FCP interface, {@code false} - * to deactivate the FCP interface - * @return This preferences object - */ - public Preferences setFcpInterfaceActive(Boolean fcpInterfaceActive) { - this.activateFcpInterface.set(fcpInterfaceActive); - if (isFcpInterfaceActive()) { - eventBus.post(new FcpInterfaceActivatedEvent()); - } else { - eventBus.post(new FcpInterfaceDeactivatedEvent()); - } - return this; - } - - /** - * Returns the action level for which full access to the FCP interface - * is required. - * - * @return The action level for which full access to the FCP interface - * is required - */ - public FullAccessRequired getFcpFullAccessRequired() { - return fcpFullAccessRequired.get(); - } - - /** - * Sets the action level for which full access to the FCP interface is - * required - * - * @param fcpFullAccessRequired - * The action level - * @return This preferences - */ - public Preferences setFcpFullAccessRequired( - FullAccessRequired fcpFullAccessRequired) { - this.fcpFullAccessRequired.set(fcpFullAccessRequired); - eventBus.post(new FullAccessRequiredChanged(getFcpFullAccessRequired())); - return this; - } - - public void saveTo(Configuration configuration) throws ConfigurationException { - configuration.getIntValue("Option/ConfigurationVersion").setValue(0); - configuration.getIntValue("Option/InsertionDelay").setValue(insertionDelay.getReal()); - configuration.getIntValue("Option/PostsPerPage").setValue(postsPerPage.getReal()); - configuration.getIntValue("Option/ImagesPerPage").setValue(imagesPerPage.getReal()); - configuration.getIntValue("Option/CharactersPerPost").setValue(charactersPerPost.getReal()); - configuration.getIntValue("Option/PostCutOffLength").setValue(postCutOffLength.getReal()); - configuration.getBooleanValue("Option/RequireFullAccess").setValue(requireFullAccess.getReal()); - configuration.getIntValue("Option/PositiveTrust").setValue(positiveTrust.getReal()); - configuration.getIntValue("Option/NegativeTrust").setValue(negativeTrust.getReal()); - configuration.getStringValue("Option/TrustComment").setValue(trustComment.getReal()); - configuration.getBooleanValue("Option/ActivateFcpInterface").setValue(activateFcpInterface.getReal()); - configuration.getIntValue("Option/FcpFullAccessRequired").setValue(toInt(fcpFullAccessRequired.getReal())); - } - - private Integer toInt(FullAccessRequired fullAccessRequired) { - return (fullAccessRequired == null) ? null : fullAccessRequired.ordinal(); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.java b/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.java index 0ae13ba..a730983 100644 --- a/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.java +++ b/src/main/java/net/pterodactylus/sone/core/PreferencesLoader.java @@ -7,8 +7,6 @@ import net.pterodactylus.util.config.ConfigurationException; /** * Loads preferences stored in a {@link Configuration} into a {@link * Preferences} object. - * - * @author David ‘Bombe’ Roden */ public class PreferencesLoader { @@ -33,31 +31,31 @@ public class PreferencesLoader { } private void loadInsertionDelay(Configuration configuration) { - preferences.setInsertionDelay(configuration.getIntValue( + preferences.setNewInsertionDelay(configuration.getIntValue( "Option/InsertionDelay").getValue(null)); } private void loadPostsPerPage(Configuration configuration) { - preferences.setPostsPerPage( + preferences.setNewPostsPerPage( configuration.getIntValue("Option/PostsPerPage") .getValue(null)); } private void loadImagesPerPage(Configuration configuration) { - preferences.setImagesPerPage( + preferences.setNewImagesPerPage( configuration.getIntValue("Option/ImagesPerPage") .getValue(null)); } private void loadCharactersPerPost(Configuration configuration) { - preferences.setCharactersPerPost( + preferences.setNewCharactersPerPost( configuration.getIntValue("Option/CharactersPerPost") .getValue(null)); } private void loadPostCutOffLength(Configuration configuration) { try { - preferences.setPostCutOffLength( + preferences.setNewPostCutOffLength( configuration.getIntValue("Option/PostCutOffLength") .getValue(null)); } catch (IllegalArgumentException iae1) { @@ -66,38 +64,38 @@ public class PreferencesLoader { } private void loadRequireFullAccess(Configuration configuration) { - preferences.setRequireFullAccess( + preferences.setNewRequireFullAccess( configuration.getBooleanValue("Option/RequireFullAccess") .getValue(null)); } private void loadPositiveTrust(Configuration configuration) { - preferences.setPositiveTrust( + preferences.setNewPositiveTrust( configuration.getIntValue("Option/PositiveTrust") .getValue(null)); } private void loadNegativeTrust(Configuration configuration) { - preferences.setNegativeTrust( + preferences.setNewNegativeTrust( configuration.getIntValue("Option/NegativeTrust") .getValue(null)); } private void loadTrustComment(Configuration configuration) { - preferences.setTrustComment( + preferences.setNewTrustComment( configuration.getStringValue("Option/TrustComment") .getValue(null)); } private void loadFcpInterfaceActive(Configuration configuration) { - preferences.setFcpInterfaceActive(configuration.getBooleanValue( + preferences.setNewFcpInterfaceActive(configuration.getBooleanValue( "Option/ActivateFcpInterface").getValue(null)); } private void loadFcpFullAccessRequired(Configuration configuration) { Integer fullAccessRequiredInteger = configuration .getIntValue("Option/FcpFullAccessRequired").getValue(null); - preferences.setFcpFullAccessRequired( + preferences.setNewFcpFullAccessRequired( (fullAccessRequiredInteger == null) ? null : FullAccessRequired.values()[fullAccessRequiredInteger]); } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java b/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java deleted file mode 100644 index efcdc6e..0000000 --- a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java +++ /dev/null @@ -1,114 +0,0 @@ -package net.pterodactylus.sone.core; - -import static com.google.common.base.Optional.absent; -import static com.google.common.base.Optional.fromNullable; -import static com.google.common.collect.FluentIterable.from; - -import java.util.Collection; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; - -/** - * Compares the contents of two {@link Sone}s and fires events for new and - * removed elements. - * - * @author David ‘Bombe’ Roden - */ -public class SoneChangeDetector { - - private final Sone oldSone; - private Optional newPostProcessor = absent(); - private Optional removedPostProcessor = absent(); - private Optional newPostReplyProcessor = absent(); - private Optional removedPostReplyProcessor = absent(); - - public SoneChangeDetector(Sone oldSone) { - this.oldSone = oldSone; - } - - public void onNewPosts(PostProcessor newPostProcessor) { - this.newPostProcessor = fromNullable(newPostProcessor); - } - - public void onRemovedPosts(PostProcessor removedPostProcessor) { - this.removedPostProcessor = fromNullable(removedPostProcessor); - } - - public void onNewPostReplies(PostReplyProcessor newPostReplyProcessor) { - this.newPostReplyProcessor = fromNullable(newPostReplyProcessor); - } - - public void onRemovedPostReplies( - PostReplyProcessor removedPostReplyProcessor) { - this.removedPostReplyProcessor = fromNullable(removedPostReplyProcessor); - } - - public void detectChanges(Sone newSone) { - processPosts(from(newSone.getPosts()).filter( - notContainedIn(oldSone.getPosts())), newPostProcessor); - processPosts(from(oldSone.getPosts()).filter( - notContainedIn(newSone.getPosts())), removedPostProcessor); - processPostReplies(from(newSone.getReplies()).filter( - notContainedIn(oldSone.getReplies())), newPostReplyProcessor); - processPostReplies(from(oldSone.getReplies()).filter( - notContainedIn(newSone.getReplies())), removedPostReplyProcessor); - } - - private void processPostReplies(FluentIterable postReplies, - Optional postReplyProcessor) { - for (PostReply postReply : postReplies) { - notifyPostReplyProcessor(postReplyProcessor, postReply); - } - } - - private void notifyPostReplyProcessor( - Optional postReplyProcessor, - PostReply postReply) { - if (postReplyProcessor.isPresent()) { - postReplyProcessor.get() - .processPostReply(postReply); - } - } - - private void processPosts(FluentIterable posts, - Optional newPostProcessor) { - for (Post post : posts) { - notifyPostProcessor(newPostProcessor, post); - } - } - - private void notifyPostProcessor(Optional postProcessor, - Post newPost) { - if (postProcessor.isPresent()) { - postProcessor.get().processPost(newPost); - } - } - - private Predicate notContainedIn(final Collection posts) { - return new Predicate() { - @Override - public boolean apply(T element) { - return !posts.contains(element); - } - }; - } - - public interface PostProcessor { - - void processPost(Post post); - - } - - public interface PostReplyProcessor { - - void processPostReply(PostReply postReply); - - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java index be0be02..0ff66fd 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java @@ -5,19 +5,19 @@ import net.pterodactylus.util.service.Service; import freenet.keys.FreenetURI; +import com.google.inject.ImplementedBy; + /** * Downloads and parses Sone and {@link Core#updateSone(Sone) updates the * core}. - * - * @author David ‘Bombe’ Roden */ +@ImplementedBy(SoneDownloaderImpl.class) public interface SoneDownloader extends Service { void addSone(Sone sone); - void fetchSone(Sone sone, FreenetURI soneUri); Sone fetchSone(Sone sone, FreenetURI soneUri, boolean fetchOnly); - Runnable fetchSoneWithUriAction(Sone sone); - Runnable fetchSoneAction(Sone sone); + Runnable fetchSoneAsUskAction(Sone sone); + Runnable fetchSoneAsSskAction(Sone sone); } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneDownloaderImpl.java b/src/main/java/net/pterodactylus/sone/core/SoneDownloaderImpl.java index db08046..ba1c632 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneDownloaderImpl.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneDownloaderImpl.java @@ -1,5 +1,5 @@ /* - * Sone - SoneDownloaderImpl.java - Copyright © 2010–2016 David Roden + * Sone - SoneDownloaderImpl.java - Copyright © 2010–2019 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 @@ -29,7 +29,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import net.pterodactylus.sone.core.FreenetInterface.Fetched; +import javax.inject.Inject; + import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.data.Sone.SoneStatus; import net.pterodactylus.util.service.AbstractService; @@ -41,15 +42,9 @@ import freenet.keys.FreenetURI; import freenet.keys.USK; import freenet.node.RequestStarter; import freenet.support.api.Bucket; -import freenet.support.io.Closer; -import com.db4o.ObjectContainer; - -import com.google.common.annotations.VisibleForTesting; /** * The Sone downloader is responsible for download Sones as they are updated. - * - * @author David ‘Bombe’ Roden */ public class SoneDownloaderImpl extends AbstractService implements SoneDownloader { @@ -60,40 +55,19 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade private static final int MAX_PROTOCOL_VERSION = 0; /** The core. */ - private final Core core; + private final UpdatedSoneProcessor updatedSoneProcessor; private final SoneParser soneParser; /** The Freenet interface. */ private final FreenetInterface freenetInterface; /** The sones to update. */ - private final Set sones = new HashSet(); - - /** - * Creates a new Sone downloader. - * - * @param core - * The core - * @param freenetInterface - * The Freenet interface - */ - public SoneDownloaderImpl(Core core, FreenetInterface freenetInterface) { - this(core, freenetInterface, new SoneParser(core)); - } + private final Set sones = new HashSet<>(); - /** - * Creates a new Sone downloader. - * - * @param core - * The core - * @param freenetInterface - * The Freenet interface - * @param soneParser - */ - @VisibleForTesting - SoneDownloaderImpl(Core core, FreenetInterface freenetInterface, SoneParser soneParser) { + @Inject + SoneDownloaderImpl(UpdatedSoneProcessor updatedSoneProcessor, FreenetInterface freenetInterface, SoneParser soneParser) { super("Sone Downloader", false); - this.core = core; + this.updatedSoneProcessor = updatedSoneProcessor; this.freenetInterface = freenetInterface; this.soneParser = soneParser; } @@ -126,7 +100,7 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade sone, key, newKnownGood, newSlotToo)); if (edition > sone.getLatestEdition()) { sone.setLatestEdition(edition); - new Thread(fetchSoneAction(sone), + new Thread(fetchSoneAsSskAction(sone), "Sone Downloader").start(); } } @@ -154,22 +128,8 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade return (currentTimeMillis() - sone.getTime()) < DAYS.toMillis(7); } - private void fetchSone(Sone sone) { - fetchSone(sone, sone.getRequestUri().sskForUSK()); - } - - /** - * Fetches the updated Sone. This method can be used to fetch a Sone from a - * specific URI. - * - * @param sone - * The Sone to fetch - * @param soneUri - * The URI to fetch the Sone from - */ - @Override - public void fetchSone(Sone sone, FreenetURI soneUri) { - fetchSone(sone, soneUri, false); + private void fetchSoneAsSsk(Sone sone) { + fetchSone(sone, sone.getRequestUri().sskForUSK(), false); } /** @@ -201,7 +161,7 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade if (parsedSone != null) { if (!fetchOnly) { parsedSone.setStatus((parsedSone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle); - core.updateSone(parsedSone); + updatedSoneProcessor.updateSone(parsedSone); addSone(parsedSone); } } @@ -231,6 +191,7 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade Sone parsedSone = soneParser.parseSone(originalSone, soneInputStream); if (parsedSone != null) { + logger.log(Level.FINER, "Sone %s was successfully parsed.", parsedSone); parsedSone.setLatestEdition(requestUri.getEdition()); } return parsedSone; @@ -244,21 +205,21 @@ public class SoneDownloaderImpl extends AbstractService implements SoneDownloade } @Override - public Runnable fetchSoneWithUriAction(final Sone sone) { + public Runnable fetchSoneAsUskAction(final Sone sone) { return new Runnable() { @Override public void run() { - fetchSone(sone, sone.getRequestUri()); + fetchSone(sone, sone.getRequestUri(), false); } }; } @Override - public Runnable fetchSoneAction(final Sone sone) { + public Runnable fetchSoneAsSskAction(final Sone sone) { return new Runnable() { @Override public void run() { - fetchSone(sone); + fetchSoneAsSsk(sone); } }; } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneException.java b/src/main/java/net/pterodactylus/sone/core/SoneException.java index e651646..e460ee7 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneException.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneException.java @@ -1,5 +1,5 @@ /* - * Sone - SoneException.java - Copyright © 2010–2016 David Roden + * Sone - SoneException.java - Copyright © 2010–2019 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 @@ -19,8 +19,6 @@ package net.pterodactylus.sone.core; /** * A Sone exception. - * - * @author David ‘Bombe’ Roden */ public class SoneException extends Exception { diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInsertException.java b/src/main/java/net/pterodactylus/sone/core/SoneInsertException.java index 879767e..8a0ff53 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInsertException.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInsertException.java @@ -1,5 +1,5 @@ /* - * Sone - SoneInsertException.java - Copyright © 2011–2016 David Roden + * Sone - SoneInsertException.java - Copyright © 2011–2019 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 @@ -19,8 +19,6 @@ package net.pterodactylus.sone.core; /** * Exception that signals a problem with an insert. - * - * @author David ‘Bombe’ Roden */ public class SoneInsertException extends SoneException { diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java index 3c32f7f..79a6259 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java @@ -1,5 +1,5 @@ /* - * Sone - SoneInserter.java - Copyright © 2010–2016 David Roden + * Sone - SoneInserter.java - Copyright © 2010–2019 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 @@ -72,8 +72,6 @@ import freenet.support.io.ArrayBucket; /** * A Sone inserter is responsible for inserting a Sone if it has changed. - * - * @author David ‘Bombe’ Roden */ public class SoneInserter extends AbstractService { @@ -280,14 +278,12 @@ public class SoneInserter extends AbstractService { * Container for information that are required to insert a Sone. This * container merely exists to copy all relevant data without holding a lock * on the {@link Sone} object for too long. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class InsertInformation implements Closeable { /** All properties of the Sone, copied for thread safety. */ - private final Map soneProperties = new HashMap(); + private final Map soneProperties = new HashMap<>(); private final String fingerprint; private final ManifestCreator manifestCreator; @@ -299,7 +295,7 @@ public class SoneInserter extends AbstractService { */ public InsertInformation(Sone sone) { this.fingerprint = sone.getFingerprint(); - Map soneProperties = new HashMap(); + Map soneProperties = new HashMap<>(); soneProperties.put("id", sone.getId()); soneProperties.put("name", sone.getName()); soneProperties.put("time", currentTimeMillis()); @@ -307,8 +303,8 @@ public class SoneInserter extends AbstractService { soneProperties.put("profile", sone.getProfile()); soneProperties.put("posts", Ordering.from(Post.NEWEST_FIRST).sortedCopy(sone.getPosts())); soneProperties.put("replies", Ordering.from(Reply.TIME_COMPARATOR).reverse().sortedCopy(sone.getReplies())); - soneProperties.put("likedPostIds", new HashSet(sone.getLikedPostIds())); - soneProperties.put("likedReplyIds", new HashSet(sone.getLikedReplyIds())); + soneProperties.put("likedPostIds", new HashSet<>(sone.getLikedPostIds())); + soneProperties.put("likedReplyIds", new HashSet<>(sone.getLikedReplyIds())); soneProperties.put("albums", FluentIterable.from(sone.getRootAlbum().getAlbums()).transformAndConcat(Album.FLATTENER).filter(NOT_EMPTY).toList()); manifestCreator = new ManifestCreator(core, soneProperties); } @@ -332,7 +328,7 @@ public class SoneInserter extends AbstractService { * @return The manifest entries for the Sone insert */ public HashMap generateManifestEntries() { - HashMap manifestEntries = new HashMap(); + HashMap manifestEntries = new HashMap<>(); /* first, create an index.html. */ manifestEntries.put("index.html", manifestCreator.createManifestElement( @@ -356,15 +352,13 @@ public class SoneInserter extends AbstractService { /** * Creates manifest elements for an insert by rendering a template. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting static class ManifestCreator implements Closeable { private final Core core; private final Map soneProperties; - private final Set buckets = new HashSet(); + private final Set buckets = new HashSet<>(); ManifestCreator(Core core, Map soneProperties) { this.core = core; diff --git a/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java b/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java index 810241a..92fa3dc 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneModificationDetector.java @@ -18,8 +18,6 @@ import com.google.common.base.Ticker; * Class that detects {@link Sone} modifications (as per their {@link * Sone#getFingerprint() fingerprints} and determines when a modified Sone may * be inserted. - * - * @author David ‘Bombe’ Roden */ class SoneModificationDetector { @@ -83,8 +81,6 @@ class SoneModificationDetector { /** * Provider for a fingerprint and the information if a {@link Sone} is locked. This * prevents us from having to lug a Sone object around. - * - * @author David ‘Bombe’ Roden */ static interface LockableFingerprintProvider { diff --git a/src/main/java/net/pterodactylus/sone/core/SoneParser.java b/src/main/java/net/pterodactylus/sone/core/SoneParser.java index fdbd9ae..1f30565 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneParser.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneParser.java @@ -14,6 +14,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import javax.inject.Inject; + import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Client; import net.pterodactylus.sone.data.Image; @@ -23,6 +25,7 @@ import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Profile.DuplicateField; import net.pterodactylus.sone.data.Profile.EmptyFieldName; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.database.Database; import net.pterodactylus.sone.database.PostBuilder; import net.pterodactylus.sone.database.PostReplyBuilder; import net.pterodactylus.sone.database.SoneBuilder; @@ -33,17 +36,16 @@ import org.w3c.dom.Document; /** * Parses a {@link Sone} from an XML {@link InputStream}. - * - * @author David ‘Bombe’ Roden */ public class SoneParser { private static final Logger logger = getLogger(SoneParser.class.getName()); private static final int MAX_PROTOCOL_VERSION = 0; - private final Core core; + private final Database database; - public SoneParser(Core core) { - this.core = core; + @Inject + public SoneParser(Database database) { + this.database = database; } public Sone parseSone(Sone originalSone, InputStream soneInputStream) throws SoneException { @@ -60,7 +62,7 @@ public class SoneParser { return null; } - SoneBuilder soneBuilder = core.soneBuilder().from(originalSone.getIdentity()); + SoneBuilder soneBuilder = database.newSoneBuilder().from(originalSone.getIdentity()); if (originalSone.isLocal()) { soneBuilder = soneBuilder.local(); } @@ -164,7 +166,7 @@ public class SoneParser { /* parse posts. */ SimpleXML postsXml = soneXml.getNode("posts"); - Set posts = new HashSet(); + Set posts = new HashSet<>(); if (postsXml == null) { /* TODO - mark Sone as bad. */ logger.log(Level.WARNING, String.format("Downloaded Sone %s has no posts!", sone)); @@ -180,7 +182,7 @@ public class SoneParser { return null; } try { - PostBuilder postBuilder = core.postBuilder(); + PostBuilder postBuilder = database.newPostBuilder(); /* TODO - parse time correctly. */ postBuilder.withId(postId).from(sone.getId()).withTime(Long.parseLong(postTime)).withText(postText); if ((postRecipientId != null) && (postRecipientId.length() == 43)) { @@ -197,7 +199,7 @@ public class SoneParser { /* parse replies. */ SimpleXML repliesXml = soneXml.getNode("replies"); - Set replies = new HashSet(); + Set replies = new HashSet<>(); if (repliesXml == null) { /* TODO - mark Sone as bad. */ logger.log(Level.WARNING, String.format("Downloaded Sone %s has no replies!", sone)); @@ -213,7 +215,7 @@ public class SoneParser { return null; } try { - PostReplyBuilder postReplyBuilder = core.postReplyBuilder(); + PostReplyBuilder postReplyBuilder = database.newPostReplyBuilder(); /* TODO - parse time correctly. */ postReplyBuilder.withId(replyId).from(sone.getId()).to(replyPostId).withTime(Long.parseLong(replyTime)).withText(replyText); replies.add(postReplyBuilder.build()); @@ -227,7 +229,7 @@ public class SoneParser { /* parse liked post IDs. */ SimpleXML likePostIdsXml = soneXml.getNode("post-likes"); - Set likedPostIds = new HashSet(); + Set likedPostIds = new HashSet<>(); if (likePostIdsXml == null) { /* TODO - mark Sone as bad. */ logger.log(Level.WARNING, String.format("Downloaded Sone %s has no post likes!", sone)); @@ -240,7 +242,7 @@ public class SoneParser { /* parse liked reply IDs. */ SimpleXML likeReplyIdsXml = soneXml.getNode("reply-likes"); - Set likedReplyIds = new HashSet(); + Set likedReplyIds = new HashSet<>(); if (likeReplyIdsXml == null) { /* TODO - mark Sone as bad. */ logger.log(Level.WARNING, String.format("Downloaded Sone %s has no reply likes!", sone)); @@ -253,8 +255,8 @@ public class SoneParser { /* parse albums. */ SimpleXML albumsXml = soneXml.getNode("albums"); - Map allImages = new HashMap(); - List topLevelAlbums = new ArrayList(); + Map allImages = new HashMap<>(); + List topLevelAlbums = new ArrayList<>(); if (albumsXml != null) { for (SimpleXML albumXml : albumsXml.getNodes("album")) { String id = albumXml.getValue("id", null); @@ -267,13 +269,13 @@ public class SoneParser { } Album parent = null; if (parentId != null) { - parent = core.getAlbum(parentId); + parent = database.getAlbum(parentId); if (parent == null) { logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone)); return null; } } - Album album = core.albumBuilder() + Album album = database.newAlbumBuilder() .withId(id) .by(sone) .build() @@ -307,7 +309,7 @@ public class SoneParser { logger.log(Level.WARNING, String.format("Downloaded Sone %s contains image %s with invalid dimensions (%s, %s)!", sone, imageId, imageWidthString, imageHeightString)); return null; } - Image image = core.imageBuilder().withId(imageId).build().modify().setSone(sone).setKey(imageKey).setCreationTime(creationTime).update(); + Image image = database.newImageBuilder().withId(imageId).build().modify().setSone(sone).setKey(imageKey).setCreationTime(creationTime).update(); image = image.modify().setTitle(imageTitle).setDescription(imageDescription).update(); image = image.modify().setWidth(imageWidth).setHeight(imageHeight).update(); album.addImage(image); diff --git a/src/main/java/net/pterodactylus/sone/core/SoneRescuer.java b/src/main/java/net/pterodactylus/sone/core/SoneRescuer.java index 0731b1a..2246ac9 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneRescuer.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneRescuer.java @@ -1,5 +1,5 @@ /* - * Sone - SoneRescuer.java - Copyright © 2011–2016 David Roden + * Sone - SoneRescuer.java - Copyright © 2011–2019 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 @@ -24,8 +24,6 @@ import freenet.keys.FreenetURI; /** * The Sone rescuer downloads older editions of a Sone and updates the currently * stored Sone with it. - * - * @author David ‘Bombe’ Roden */ public class SoneRescuer extends AbstractService { diff --git a/src/main/java/net/pterodactylus/sone/core/SoneUri.java b/src/main/java/net/pterodactylus/sone/core/SoneUri.java index 1fbadbc..373077f 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneUri.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneUri.java @@ -1,5 +1,5 @@ /* - * Sone - SoneUri.java - Copyright © 2013–2016 David Roden + * Sone - SoneUri.java - Copyright © 2013–2019 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 @@ -28,8 +28,6 @@ import freenet.keys.FreenetURI; /** * Helper class that creates {@link FreenetURI}s for Sone to insert to and * request from. - * - * @author David ‘Bombe’ Roden */ public class SoneUri { diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java index e739a44..9f6963f 100644 --- a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java +++ b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java @@ -1,5 +1,5 @@ /* - * Sone - UpdateChecker.java - Copyright © 2011–2016 David Roden + * Sone - UpdateChecker.java - Copyright © 2011–2019 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 @@ -30,8 +30,8 @@ import java.util.logging.Logger; import javax.inject.Singleton; -import net.pterodactylus.sone.core.FreenetInterface.Fetched; import net.pterodactylus.sone.core.event.UpdateFoundEvent; +import net.pterodactylus.sone.main.PluginHomepage; import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.util.io.Closer; import net.pterodactylus.util.version.Version; @@ -44,8 +44,6 @@ import freenet.support.api.Bucket; /** * Watches the official Sone homepage for new releases. - * - * @author David ‘Bombe’ Roden */ @Singleton public class UpdateChecker { @@ -72,6 +70,8 @@ public class UpdateChecker { /** The release date of the latest version. */ private long latestVersionDate; + private final PluginHomepage pluginHomepage; + /** * Creates a new update checker. * @@ -81,11 +81,12 @@ public class UpdateChecker { * The freenet interface to use */ @Inject - public UpdateChecker(EventBus eventBus, FreenetInterface freenetInterface, Version currentVersion) { + public UpdateChecker(EventBus eventBus, FreenetInterface freenetInterface, Version currentVersion, PluginHomepage pluginHomepage) { this.eventBus = eventBus; this.freenetInterface = freenetInterface; this.currentRunningVersion = currentVersion; this.currentLatestVersion = currentVersion; + this.pluginHomepage = pluginHomepage; } // @@ -141,7 +142,7 @@ public class UpdateChecker { */ public void start() { try { - currentUri = new FreenetURI(SonePlugin.getHomepage()); + currentUri = new FreenetURI(pluginHomepage.getHomepage()); } catch (MalformedURLException mue1) { /* this can not really happen unless I screw up. */ logger.log(Level.SEVERE, "Sone Homepage URI invalid!", mue1); diff --git a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java index 908bd96..35c3203 100644 --- a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java +++ b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java @@ -8,8 +8,6 @@ import com.google.inject.ImplementedBy; /** * Updates WebOfTrust identity data. - * - * @author David ‘Bombe’ Roden */ @ImplementedBy(WebOfTrustUpdaterImpl.class) public interface WebOfTrustUpdater extends Service { diff --git a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdaterImpl.java b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdaterImpl.java index 05d940f..809ca20 100644 --- a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdaterImpl.java +++ b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdaterImpl.java @@ -1,5 +1,5 @@ /* - * Sone - WebOfTrustUpdaterImpl.java - Copyright © 2013–2016 David Roden + * Sone - WebOfTrustUpdaterImpl.java - Copyright © 2013–2019 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 @@ -40,8 +40,6 @@ import com.google.inject.Singleton; /** * Updates WebOfTrust identity data in a background thread because communicating * with the WebOfTrust plugin can potentially last quite long. - * - * @author David ‘Bombe’ Roden */ @Singleton public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrustUpdater { @@ -57,7 +55,7 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust private final WebOfTrustConnector webOfTrustConnector; /** The queue for jobs. */ - private final BlockingQueue updateJobs = new LinkedBlockingQueue(); + private final BlockingQueue updateJobs = new LinkedBlockingQueue<>(); /** * Creates a new trust updater. @@ -229,8 +227,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * Base class for WebOfTrust update jobs. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class WebOfTrustUpdateJob implements Runnable { @@ -302,8 +298,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * Update job that sets the trust relation between two identities. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class SetTrustJob extends WebOfTrustUpdateJob { @@ -389,8 +383,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * Base class for context updates of an {@link OwnIdentity}. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob { @@ -445,8 +437,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * Job that adds a context to an {@link OwnIdentity}. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class AddContextJob extends WebOfTrustContextUpdateJob { @@ -481,8 +471,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * Job that removes a context from an {@link OwnIdentity}. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class RemoveContextJob extends WebOfTrustContextUpdateJob { @@ -517,8 +505,6 @@ public class WebOfTrustUpdaterImpl extends AbstractService implements WebOfTrust /** * WebOfTrust update job that sets a property on an {@link OwnIdentity}. - * - * @author David ‘Bombe’ Roden */ @VisibleForTesting class SetPropertyJob extends WebOfTrustUpdateJob { diff --git a/src/main/java/net/pterodactylus/sone/core/event/ImageEvent.java b/src/main/java/net/pterodactylus/sone/core/event/ImageEvent.java index a8a0c6f..6daef1a 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/ImageEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/ImageEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ImageEvent.java - Copyright © 2013–2016 David Roden + * Sone - ImageEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Image; /** * Base class for {@link Image} events. - * - * @author David ‘Bombe’ Roden */ public abstract class ImageEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertAbortedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertAbortedEvent.java index 63a561b..2bfa3a2 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertAbortedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertAbortedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ImageInsertAbortedEvent.java - Copyright © 2013–2016 David Roden + * Sone - ImageInsertAbortedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Image; /** * Event that signals that an {@link Image} insert is aborted. - * - * @author David ‘Bombe’ Roden */ public class ImageInsertAbortedEvent extends ImageEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFailedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFailedEvent.java index eaa3996..430c64b 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFailedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFailedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ImageInsertFailedEvent.java - Copyright © 2013–2016 David Roden + * Sone - ImageInsertFailedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Image; /** * Event that signals that an {@link Image} insert has failed. - * - * @author David ‘Bombe’ Roden */ public class ImageInsertFailedEvent extends ImageEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFinishedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFinishedEvent.java index 41d7ecc..4419311 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFinishedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertFinishedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ImageInsertFinishedEvent.java - Copyright © 2013–2016 David Roden + * Sone - ImageInsertFinishedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import freenet.keys.FreenetURI; /** * Event that signals that an {@link Image} insert is finished. - * - * @author David ‘Bombe’ Roden */ public class ImageInsertFinishedEvent extends ImageEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertStartedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertStartedEvent.java index 876f2db..ac9e3e3 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/ImageInsertStartedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/ImageInsertStartedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ImageInsertStartedEvent.java - Copyright © 2013–2016 David Roden + * Sone - ImageInsertStartedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Image; /** * Event that signals that an {@link Image} is not being inserted. - * - * @author David ‘Bombe’ Roden */ public class ImageInsertStartedEvent extends ImageEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.java deleted file mode 100644 index a3dc2ce..0000000 --- a/src/main/java/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.pterodactylus.sone.core.event; - -import com.google.common.eventbus.EventBus; - -/** - * Notifies interested {@link EventBus} clients that the Sone insertion delay - * has changed. - * - * @author David ‘Bombe’ Roden - */ -public class InsertionDelayChangedEvent { - - private final int insertionDelay; - - public InsertionDelayChangedEvent(int insertionDelay) { - this.insertionDelay = insertionDelay; - } - - public int getInsertionDelay() { - return insertionDelay; - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/event/MarkPostKnownEvent.java b/src/main/java/net/pterodactylus/sone/core/event/MarkPostKnownEvent.java index 72c7baf..7c8a6c3 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/MarkPostKnownEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/MarkPostKnownEvent.java @@ -1,5 +1,5 @@ /* - * Sone - MarkPostKnownEvent.java - Copyright © 2013–2016 David Roden + * Sone - MarkPostKnownEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.data.Post; /** * Event that signals that a {@link Post} has been marked as * {@link Post#isKnown() known}. - * - * @author David ‘Bombe’ Roden */ public class MarkPostKnownEvent extends PostEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/MarkPostReplyKnownEvent.java b/src/main/java/net/pterodactylus/sone/core/event/MarkPostReplyKnownEvent.java index 224bb31..4c0e2fc 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/MarkPostReplyKnownEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/MarkPostReplyKnownEvent.java @@ -1,5 +1,5 @@ /* - * Sone - MarkPostReplyKnownEvent.java - Copyright © 2013–2016 David Roden + * Sone - MarkPostReplyKnownEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.data.PostReply; /** * Event that signals that a {@link PostReply} has been marked as * {@link PostReply#isKnown() known}. - * - * @author David ‘Bombe’ Roden */ public class MarkPostReplyKnownEvent extends PostReplyEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/MarkSoneKnownEvent.java b/src/main/java/net/pterodactylus/sone/core/event/MarkSoneKnownEvent.java index ca6cd70..5bbdf5e 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/MarkSoneKnownEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/MarkSoneKnownEvent.java @@ -1,5 +1,5 @@ /* - * Sone - MarkSoneKnownEvent.java - Copyright © 2013–2016 David Roden + * Sone - MarkSoneKnownEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} has been marked as * {@link Sone#isKnown() known}. - * - * @author David ‘Bombe’ Roden */ public class MarkSoneKnownEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/NewPostFoundEvent.java b/src/main/java/net/pterodactylus/sone/core/event/NewPostFoundEvent.java deleted file mode 100644 index ff81357..0000000 --- a/src/main/java/net/pterodactylus/sone/core/event/NewPostFoundEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - NewPostFoundEvent.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.core.event; - -import net.pterodactylus.sone.data.Post; - -/** - * Event that signals that a new post was found. - * - * @author David ‘Bombe’ Roden - */ -public class NewPostFoundEvent extends PostEvent { - - /** - * Creates a new “new post found” event. - * - * @param post - * The post that was found - */ - public NewPostFoundEvent(Post post) { - super(post); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.java b/src/main/java/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.java deleted file mode 100644 index bda02b6..0000000 --- a/src/main/java/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - NewPostReplyFoundEvent.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.core.event; - -import net.pterodactylus.sone.data.PostReply; - -/** - * Event that signals that a new {@link PostReply} was found. - * - * @author David ‘Bombe’ Roden - */ -public class NewPostReplyFoundEvent extends PostReplyEvent { - - /** - * Creates a new “new post found” event. - * - * @param postReply - * The post reply that was found - */ - public NewPostReplyFoundEvent(PostReply postReply) { - super(postReply); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/event/NewSoneFoundEvent.java b/src/main/java/net/pterodactylus/sone/core/event/NewSoneFoundEvent.java index c110483..8fb17d2 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/NewSoneFoundEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/NewSoneFoundEvent.java @@ -1,5 +1,5 @@ /* - * Sone - NewSoneFoundEvent.java - Copyright © 2013–2016 David Roden + * Sone - NewSoneFoundEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a new remote Sone was found. - * - * @author David ‘Bombe’ Roden */ public class NewSoneFoundEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/PostEvent.java b/src/main/java/net/pterodactylus/sone/core/event/PostEvent.java index 78555b5..93a61c6 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/PostEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/PostEvent.java @@ -1,5 +1,5 @@ /* - * Sone - PostEvent.java - Copyright © 2013–2016 David Roden + * Sone - PostEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Post; /** * Base class for post events. - * - * @author David ‘Bombe’ Roden */ public class PostEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/PostRemovedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/PostRemovedEvent.java deleted file mode 100644 index 8240176..0000000 --- a/src/main/java/net/pterodactylus/sone/core/event/PostRemovedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - PostRemovedEvent.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.core.event; - -import net.pterodactylus.sone.data.Post; - -/** - * Event that signals that a {@link Post} was removed. - * - * @author David ‘Bombe’ Roden - */ -public class PostRemovedEvent extends PostEvent { - - /** - * Creates a new “post removed” event. - * - * @param post - * The post that was removed - */ - public PostRemovedEvent(Post post) { - super(post); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/event/PostReplyEvent.java b/src/main/java/net/pterodactylus/sone/core/event/PostReplyEvent.java index 6ae51bc..e31870b 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/PostReplyEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/PostReplyEvent.java @@ -1,5 +1,5 @@ /* - * Sone - PostReplyEvent.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.PostReply; /** * Base class for {@link PostReply} events. - * - * @author David ‘Bombe’ Roden */ public class PostReplyEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.java deleted file mode 100644 index 4f7cc8b..0000000 --- a/src/main/java/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - PostReplyRemovedEvent.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.core.event; - -import net.pterodactylus.sone.data.PostReply; - -/** - * Event that signals that a {@link PostReply} was removed. - * - * @author David ‘Bombe’ Roden - */ -public class PostReplyRemovedEvent extends PostReplyEvent { - - /** - * Creates a new “post reply removed” event. - * - * @param postReply - * The post reply that was removed - */ - public PostReplyRemovedEvent(PostReply postReply) { - super(postReply); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneEvent.java index 848c1b8..b7497ff 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Base class for Sone events. - * - * @author David ‘Bombe’ Roden */ public abstract class SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertAbortedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertAbortedEvent.java index a20e15a..a8c9bb6 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertAbortedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertAbortedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneInsertAbortedEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneInsertAbortedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} insert was aborted. - * - * @author David ‘Bombe’ Roden */ public class SoneInsertAbortedEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertedEvent.java index 8b3f79e..53fa935 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneInsertedEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneInsertedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} was inserted. - * - * @author David ‘Bombe’ Roden */ public class SoneInsertedEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertingEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertingEvent.java index 4e2f155..a9ef6fb 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneInsertingEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneInsertingEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneInsertingEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneInsertingEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} is now being inserted. - * - * @author David ‘Bombe’ Roden */ public class SoneInsertingEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneLockedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneLockedEvent.java index 2703f16..cdc9e3a 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneLockedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneLockedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneLockedEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneLockedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} was locked. Only * {@link Sone#isLocal() local Sones} can be locked. - * - * @author David ‘Bombe’ Roden */ public class SoneLockedEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneRemovedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneRemovedEvent.java index ecba776..e46272d 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneRemovedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneRemovedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneRemovedEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneRemovedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} was removed. - * - * @author David ‘Bombe’ Roden */ public class SoneRemovedEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/SoneUnlockedEvent.java b/src/main/java/net/pterodactylus/sone/core/event/SoneUnlockedEvent.java index de2d875..106d32d 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/SoneUnlockedEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/SoneUnlockedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - SoneUnlockedEvent.java - Copyright © 2013–2016 David Roden + * Sone - SoneUnlockedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.data.Sone; /** * Event that signals that a {@link Sone} was unlocked. Only * {@link Sone#isLocal() local Sones} can be locked. - * - * @author David ‘Bombe’ Roden */ public class SoneUnlockedEvent extends SoneEvent { diff --git a/src/main/java/net/pterodactylus/sone/core/event/UpdateFoundEvent.java b/src/main/java/net/pterodactylus/sone/core/event/UpdateFoundEvent.java index 10adda5..2884090 100644 --- a/src/main/java/net/pterodactylus/sone/core/event/UpdateFoundEvent.java +++ b/src/main/java/net/pterodactylus/sone/core/event/UpdateFoundEvent.java @@ -1,5 +1,5 @@ /* - * Sone - UpdateFoundEvent.java - Copyright © 2013–2016 David Roden + * Sone - UpdateFoundEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.util.version.Version; /** * Event that signals that an update for Sone was found. - * - * @author David ‘Bombe’ Roden */ public class UpdateFoundEvent { diff --git a/src/main/java/net/pterodactylus/sone/data/Album.java b/src/main/java/net/pterodactylus/sone/data/Album.java index 5a02f19..c4af294 100644 --- a/src/main/java/net/pterodactylus/sone/data/Album.java +++ b/src/main/java/net/pterodactylus/sone/data/Album.java @@ -1,5 +1,5 @@ /* - * Sone - Album.java - Copyright © 2011–2016 David Roden + * Sone - Album.java - Copyright © 2011–2019 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 @@ -22,7 +22,6 @@ import static java.util.Collections.emptyList; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import javax.annotation.Nonnull; @@ -33,20 +32,9 @@ import com.google.common.collect.ImmutableList; /** * Container for images that can also contain nested {@link Album}s. - * - * @author David ‘Bombe’ Roden */ public interface Album extends Identified, Fingerprintable { - /** Compares two {@link Album}s by {@link #getTitle()}. */ - Comparator TITLE_COMPARATOR = new Comparator() { - - @Override - public int compare(Album leftAlbum, Album rightAlbum) { - return leftAlbum.getTitle().compareToIgnoreCase(rightAlbum.getTitle()); - } - }; - /** Function that flattens the given album and all albums beneath it. */ Function> FLATTENER = new Function>() { @@ -56,7 +44,7 @@ public interface Album extends Identified, Fingerprintable { if (album == null) { return emptyList(); } - List albums = new ArrayList(); + List albums = new ArrayList<>(); albums.add(album); for (Album subAlbum : album.getAlbums()) { albums.addAll(FluentIterable.from(ImmutableList.of(subAlbum)).transformAndConcat(FLATTENER).toList()); @@ -271,8 +259,6 @@ public interface Album extends Identified, Fingerprintable { * Allows modifying an album. Modifications are only performed once {@link * #update()} has succesfully returned a new album with the modifications * made. - * - * @author David ‘Bombe’ Roden */ interface Modifier { diff --git a/src/main/java/net/pterodactylus/sone/data/Client.java b/src/main/java/net/pterodactylus/sone/data/Client.java index 650ef16..f23decf 100644 --- a/src/main/java/net/pterodactylus/sone/data/Client.java +++ b/src/main/java/net/pterodactylus/sone/data/Client.java @@ -1,5 +1,5 @@ /* - * Sone - Client.java - Copyright © 2010–2016 David Roden + * Sone - Client.java - Copyright © 2010–2019 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 @@ -23,8 +23,6 @@ import com.google.common.base.Objects; /** * Container for the client information of a {@link Sone}. - * - * @author David ‘Bombe’ Roden */ public class Client { diff --git a/src/main/java/net/pterodactylus/sone/data/Fingerprintable.java b/src/main/java/net/pterodactylus/sone/data/Fingerprintable.java deleted file mode 100644 index 407aa8a..0000000 --- a/src/main/java/net/pterodactylus/sone/data/Fingerprintable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Sone - Fingerprintable.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.data; - -/** - * Interface for objects that can create a fingerprint of themselves, e.g. to - * detect modifications. The fingerprint should only contain original - * information; derived information should not be included. - * - * @author David ‘Bombe’ Roden - */ -public interface Fingerprintable { - - /** - * Returns the fingerprint of this object. - * - * @return The fingerprint of this object - */ - public String getFingerprint(); - -} diff --git a/src/main/java/net/pterodactylus/sone/data/Identified.java b/src/main/java/net/pterodactylus/sone/data/Identified.java deleted file mode 100644 index 659a56f..0000000 --- a/src/main/java/net/pterodactylus/sone/data/Identified.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Sone - Identified.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.data; - -import javax.annotation.Nonnull; - -import com.google.common.base.Function; -import com.google.common.base.Optional; - -/** - * Interface for all objects that expose an ID. - * - * @author David ‘Bombe’ Roden - */ -public interface Identified { - - /** Function to extract the ID from an optional. */ - public static final Function, Optional> GET_ID = new Function, Optional>() { - - @Override - @Nonnull - public Optional apply(Optional identified) { - return (identified == null) ? Optional.absent() : (identified.isPresent() ? Optional.of(identified.get().getId()) : Optional.absent()); - } - }; - - /** - * Returns the ID of this element. - * - * @return The ID of this element - */ - public String getId(); - -} diff --git a/src/main/java/net/pterodactylus/sone/data/Image.java b/src/main/java/net/pterodactylus/sone/data/Image.java index 55b0094..93d0702 100644 --- a/src/main/java/net/pterodactylus/sone/data/Image.java +++ b/src/main/java/net/pterodactylus/sone/data/Image.java @@ -1,5 +1,5 @@ /* - * Sone - Image.java - Copyright © 2011–2016 David Roden + * Sone - Image.java - Copyright © 2011–2019 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 @@ -19,8 +19,6 @@ package net.pterodactylus.sone.data; /** * Container for image metadata. - * - * @author David Roden */ public interface Image extends Identified, Fingerprintable { diff --git a/src/main/java/net/pterodactylus/sone/data/Post.java b/src/main/java/net/pterodactylus/sone/data/Post.java index 5a1c2c5..b6648e2 100644 --- a/src/main/java/net/pterodactylus/sone/data/Post.java +++ b/src/main/java/net/pterodactylus/sone/data/Post.java @@ -1,5 +1,5 @@ /* - * Sone - Post.java - Copyright © 2010–2016 David Roden + * Sone - Post.java - Copyright © 2010–2019 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 @@ -27,8 +27,6 @@ import com.google.common.base.Predicate; /** * A post is a short message that a user writes in his Sone to let other users * know what is going on. - * - * @author David ‘Bombe’ Roden */ public interface Post extends Identified { @@ -126,9 +124,6 @@ public interface Post extends Identified { /** * Shell for a post that has not yet been loaded. - * - * @author David ‘Bombe’ - * Roden */ public static class EmptyPost implements Post { diff --git a/src/main/java/net/pterodactylus/sone/data/PostReply.java b/src/main/java/net/pterodactylus/sone/data/PostReply.java index 6821b7b..dc4a903 100644 --- a/src/main/java/net/pterodactylus/sone/data/PostReply.java +++ b/src/main/java/net/pterodactylus/sone/data/PostReply.java @@ -1,5 +1,5 @@ /* - * Sone - PostReply.java - Copyright © 2010–2016 David Roden + * Sone - PostReply.java - Copyright © 2010–2019 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 @@ -23,8 +23,6 @@ import com.google.common.base.Predicate; /** * A reply is like a {@link Post} but can never be posted on its own, it always * refers to another {@link Post}. - * - * @author David ‘Bombe’ Roden */ public interface PostReply extends Reply { diff --git a/src/main/java/net/pterodactylus/sone/data/Profile.java b/src/main/java/net/pterodactylus/sone/data/Profile.java index a0ebeba..8ea09f7 100644 --- a/src/main/java/net/pterodactylus/sone/data/Profile.java +++ b/src/main/java/net/pterodactylus/sone/data/Profile.java @@ -1,5 +1,5 @@ /* - * Sone - Profile.java - Copyright © 2010–2016 David Roden + * Sone - Profile.java - Copyright © 2010–2019 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 @@ -20,6 +20,7 @@ package net.pterodactylus.sone.data; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static java.nio.charset.StandardCharsets.UTF_8; import java.util.ArrayList; import java.util.Collections; @@ -35,8 +36,6 @@ import com.google.common.hash.Hashing; /** * A profile stores personal information about a {@link Sone}. All information * is optional and can be {@code null}. - * - * @author David ‘Bombe’ Roden */ public class Profile implements Fingerprintable { @@ -128,7 +127,7 @@ public class Profile implements Fingerprintable { */ @Nonnull public Profile setFirstName(@Nullable String firstName) { - this.firstName = firstName; + this.firstName = "".equals(firstName) ? null : firstName; return this; } @@ -151,7 +150,7 @@ public class Profile implements Fingerprintable { */ @Nonnull public Profile setMiddleName(@Nullable String middleName) { - this.middleName = middleName; + this.middleName = "".equals(middleName) ? null : middleName; return this; } @@ -174,7 +173,7 @@ public class Profile implements Fingerprintable { */ @Nonnull public Profile setLastName(@Nullable String lastName) { - this.lastName = lastName; + this.lastName = "".equals(lastName) ? null : lastName; return this; } @@ -284,7 +283,7 @@ public class Profile implements Fingerprintable { */ @Nonnull public List getFields() { - return new ArrayList(fields); + return new ArrayList<>(fields); } /** @@ -431,42 +430,40 @@ public class Profile implements Fingerprintable { @Override public String getFingerprint() { Hasher hash = Hashing.sha256().newHasher(); - hash.putString("Profile("); + hash.putString("Profile(", UTF_8); if (firstName != null) { - hash.putString("FirstName(").putString(firstName).putString(")"); + hash.putString("FirstName(", UTF_8).putString(firstName, UTF_8).putString(")", UTF_8); } if (middleName != null) { - hash.putString("MiddleName(").putString(middleName).putString(")"); + hash.putString("MiddleName(", UTF_8).putString(middleName, UTF_8).putString(")", UTF_8); } if (lastName != null) { - hash.putString("LastName(").putString(lastName).putString(")"); + hash.putString("LastName(", UTF_8).putString(lastName, UTF_8).putString(")", UTF_8); } if (birthDay != null) { - hash.putString("BirthDay(").putInt(birthDay).putString(")"); + hash.putString("BirthDay(", UTF_8).putInt(birthDay).putString(")", UTF_8); } if (birthMonth != null) { - hash.putString("BirthMonth(").putInt(birthMonth).putString(")"); + hash.putString("BirthMonth(", UTF_8).putInt(birthMonth).putString(")", UTF_8); } if (birthYear != null) { - hash.putString("BirthYear(").putInt(birthYear).putString(")"); + hash.putString("BirthYear(", UTF_8).putInt(birthYear).putString(")", UTF_8); } if (avatar != null) { - hash.putString("Avatar(").putString(avatar).putString(")"); + hash.putString("Avatar(", UTF_8).putString(avatar, UTF_8).putString(")", UTF_8); } - hash.putString("ContactInformation("); + hash.putString("ContactInformation(", UTF_8); for (Field field : fields) { - hash.putString(field.getName()).putString("(").putString(field.getValue()).putString(")"); + hash.putString(field.getName(), UTF_8).putString("(", UTF_8).putString(field.getValue(), UTF_8).putString(")", UTF_8); } - hash.putString(")"); - hash.putString(")"); + hash.putString(")", UTF_8); + hash.putString(")", UTF_8); return hash.hash().toString(); } /** * Container for a profile field. - * - * @author David ‘Bombe’ Roden */ public class Field { @@ -586,15 +583,11 @@ public class Profile implements Fingerprintable { /** * Exception that signals the addition of a field with an empty name. - * - * @author David ‘Bombe’ Roden */ public static class EmptyFieldName extends IllegalArgumentException { } /** * Exception that signals the addition of a field that already exists. - * - * @author David ‘Bombe’ Roden */ public static class DuplicateField extends IllegalArgumentException { } diff --git a/src/main/java/net/pterodactylus/sone/data/Reply.java b/src/main/java/net/pterodactylus/sone/data/Reply.java index d3068c4..c596605 100644 --- a/src/main/java/net/pterodactylus/sone/data/Reply.java +++ b/src/main/java/net/pterodactylus/sone/data/Reply.java @@ -1,5 +1,5 @@ /* - * Sone - Reply.java - Copyright © 2010–2016 David Roden + * Sone - Reply.java - Copyright © 2010–2019 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 @@ -26,7 +26,6 @@ import com.google.common.base.Predicate; * * @param * The type of the reply - * @author David ‘Bombe’ Roden */ public interface Reply> extends Identified { diff --git a/src/main/java/net/pterodactylus/sone/data/Sone.java b/src/main/java/net/pterodactylus/sone/data/Sone.java index b761c7b..273b73e 100644 --- a/src/main/java/net/pterodactylus/sone/data/Sone.java +++ b/src/main/java/net/pterodactylus/sone/data/Sone.java @@ -1,5 +1,5 @@ /* - * Sone - Sone.java - Copyright © 2010–2016 David Roden + * Sone - Sone.java - Copyright © 2010–2019 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 @@ -44,15 +44,11 @@ import com.google.common.primitives.Ints; /** * A Sone defines everything about a user: her profile, her status updates, her * replies, her likes and dislikes, etc. - * - * @author David ‘Bombe’ Roden */ public interface Sone extends Identified, Fingerprintable, Comparable { /** * Enumeration for the possible states of a {@link Sone}. - * - * @author David ‘Bombe’ Roden */ public enum SoneStatus { diff --git a/src/main/java/net/pterodactylus/sone/data/SoneOptions.java b/src/main/java/net/pterodactylus/sone/data/SoneOptions.java index 5f05447..d7089d9 100644 --- a/src/main/java/net/pterodactylus/sone/data/SoneOptions.java +++ b/src/main/java/net/pterodactylus/sone/data/SoneOptions.java @@ -6,8 +6,6 @@ import javax.annotation.Nonnull; /** * All Sone-specific options. - * - * @author David ‘Bombe’ Roden */ public interface SoneOptions { @@ -34,8 +32,6 @@ public interface SoneOptions { /** * Possible values for all options that are related to loading external content. - * - * @author David ‘Bombe’ Roden */ enum LoadExternalContent { @@ -58,8 +54,6 @@ public interface SoneOptions { /** * {@link SoneOptions} implementation. - * - * @author David ‘Bombe’ Roden */ public class DefaultSoneOptions implements SoneOptions { diff --git a/src/main/java/net/pterodactylus/sone/data/TemporaryImage.java b/src/main/java/net/pterodactylus/sone/data/TemporaryImage.java index ee6c35c..378a348 100644 --- a/src/main/java/net/pterodactylus/sone/data/TemporaryImage.java +++ b/src/main/java/net/pterodactylus/sone/data/TemporaryImage.java @@ -1,5 +1,5 @@ /* - * Sone - TemporaryImage.java - Copyright © 2011–2016 David Roden + * Sone - TemporaryImage.java - Copyright © 2011–2019 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 @@ -25,8 +25,6 @@ import java.util.UUID; /** * A temporary image stores an uploaded image in memory until it has been * inserted into Freenet and is subsequently loaded from there. - * - * @author David ‘Bombe’ Roden */ public class TemporaryImage { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractAlbumBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractAlbumBuilder.java index 66a758a..460be4e 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractAlbumBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractAlbumBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractAlbumBuilder.java - Copyright © 2013–2016 David Roden + * Sone - AbstractAlbumBuilder.java - Copyright © 2013–2019 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 @@ -25,8 +25,6 @@ import net.pterodactylus.sone.database.AlbumBuilder; /** * Abstract {@link AlbumBuilder} implementation. It stores the state of the new * album and performs validation, you only need to implement {@link #build()}. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractAlbumBuilder implements AlbumBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractImageBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractImageBuilder.java index 2282c11..f545ae9 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractImageBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractImageBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractImageBuilder.java - Copyright © 2013–2016 David Roden + * Sone - AbstractImageBuilder.java - Copyright © 2013–2019 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 @@ -23,8 +23,6 @@ import net.pterodactylus.sone.database.ImageBuilder; /** * Abstract {@link ImageBuilder} implementation. It stores the state of the new * album and performs validation, you only need to implement {@link #build()}. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractImageBuilder implements ImageBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostBuilder.java index 9e2c50a..cabe8d5 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractPostBuilder.java - Copyright © 2013–2016 David Roden + * Sone - AbstractPostBuilder.java - Copyright © 2013–2019 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 @@ -26,8 +26,6 @@ import net.pterodactylus.sone.database.SoneProvider; /** * Abstract {@link PostBuilder} implementation. It stores the state of the new * post and performs validation, you only need to implement {@link #build()}. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractPostBuilder implements PostBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostReplyBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostReplyBuilder.java index bd8090f..0fe124e 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostReplyBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractPostReplyBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractPostReplyBuilder.java - Copyright © 2013–2016 David Roden + * Sone - AbstractPostReplyBuilder.java - Copyright © 2013–2019 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 @@ -25,8 +25,6 @@ import net.pterodactylus.sone.database.PostReplyBuilder; * Abstract {@link PostReplyBuilder} implementation. It stores the state of the * new post and performs validation, implementations only need to implement * {@link #build()}. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractPostReplyBuilder extends AbstractReplyBuilder implements PostReplyBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java index c66debf..052ca2d 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractReplyBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractReplyBuilder.java - Copyright © 2013–2016 David Roden + * Sone - AbstractReplyBuilder.java - Copyright © 2013–2019 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 @@ -24,7 +24,6 @@ import net.pterodactylus.sone.database.ReplyBuilder; * * @param * The interface implemented and exposed by the builder - * @author David ‘Bombe’ Roden */ public class AbstractReplyBuilder> implements ReplyBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilder.java b/src/main/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilder.java index a214677..f6d091d 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilder.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilder.java @@ -8,8 +8,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Abstract {@link SoneBuilder} implementation. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractSoneBuilder implements SoneBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AlbumBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/AlbumBuilderImpl.java index 3ec6b42..601daa8 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AlbumBuilderImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AlbumBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Sone - AlbumBuilderImpl.java - Copyright © 2013–2016 David Roden + * Sone - AlbumBuilderImpl.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.database.AlbumBuilder; /** * {@link AlbumBuilder} implementation that creates {@link AlbumImpl} objects. - * - * @author David ‘Bombe’ Roden */ public class AlbumBuilderImpl extends AbstractAlbumBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java index 991459a..3ec362f 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/AlbumImpl.java @@ -1,5 +1,5 @@ /* - * Sone - AlbumImpl.java - Copyright © 2011–2016 David Roden + * Sone - AlbumImpl.java - Copyright © 2011–2019 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 @@ -21,6 +21,7 @@ import static com.google.common.base.Optional.absent; import static com.google.common.base.Optional.fromNullable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.nio.charset.StandardCharsets.UTF_8; import java.util.ArrayList; import java.util.HashMap; @@ -41,8 +42,6 @@ import com.google.common.hash.Hashing; /** * Container for images that can also contain nested {@link AlbumImpl}s. - * - * @author David ‘Bombe’ Roden */ public class AlbumImpl implements Album { @@ -53,13 +52,13 @@ public class AlbumImpl implements Album { private final Sone sone; /** Nested albums. */ - private final List albums = new ArrayList(); + private final List albums = new ArrayList<>(); /** The image IDs in order. */ - private final List imageIds = new ArrayList(); + private final List imageIds = new ArrayList<>(); /** The images in this album. */ - private final Map images = new HashMap(); + private final Map images = new HashMap<>(); /** The parent album. */ private Album parent; @@ -102,7 +101,7 @@ public class AlbumImpl implements Album { @Override public List getAlbums() { - return new ArrayList(albums); + return new ArrayList<>(albums); } @Override @@ -154,7 +153,7 @@ public class AlbumImpl implements Album { @Override public List getImages() { - return new ArrayList(Collections2.filter(Collections2.transform(imageIds, new Function() { + return new ArrayList<>(Collections2.filter(Collections2.transform(imageIds, new Function() { @Override @SuppressWarnings("synthetic-access") @@ -298,28 +297,28 @@ public class AlbumImpl implements Album { @Override public String getFingerprint() { Hasher hash = Hashing.sha256().newHasher(); - hash.putString("Album("); - hash.putString("ID(").putString(id).putString(")"); - hash.putString("Title(").putString(title).putString(")"); - hash.putString("Description(").putString(description).putString(")"); + hash.putString("Album(", UTF_8); + hash.putString("ID(", UTF_8).putString(id, UTF_8).putString(")", UTF_8); + hash.putString("Title(", UTF_8).putString(title, UTF_8).putString(")", UTF_8); + hash.putString("Description(", UTF_8).putString(description, UTF_8).putString(")", UTF_8); /* add nested albums. */ - hash.putString("Albums("); + hash.putString("Albums(", UTF_8); for (Album album : albums) { - hash.putString(album.getFingerprint()); + hash.putString(album.getFingerprint(), UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); /* add images. */ - hash.putString("Images("); + hash.putString("Images(", UTF_8); for (Image image : getImages()) { if (image.isInserted()) { - hash.putString(image.getFingerprint()); + hash.putString(image.getFingerprint(), UTF_8); } } - hash.putString(")"); + hash.putString(")", UTF_8); - hash.putString(")"); + hash.putString(")", UTF_8); return hash.hash().toString(); } diff --git a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java deleted file mode 100644 index 65b266d..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostBuilderFactory.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Sone - DefaultPostBuilderFactory.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import net.pterodactylus.sone.database.PostBuilder; -import net.pterodactylus.sone.database.PostBuilderFactory; -import net.pterodactylus.sone.database.SoneProvider; - -import com.google.inject.Inject; - -/** - * {@link PostBuilderFactory} implementation that creates - * {@link PostBuilderImpl}s. - * - * @author David ‘Bombe’ Roden - */ -public class DefaultPostBuilderFactory implements PostBuilderFactory { - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** - * Creates a new default post builder factory. - * - * @param soneProvider - * The Sone provider - */ - @Inject - public DefaultPostBuilderFactory(SoneProvider soneProvider) { - this.soneProvider = soneProvider; - } - - /** - * {@inheritDoc} - */ - @Override - public PostBuilder newPostBuilder() { - return new PostBuilderImpl(soneProvider); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java deleted file mode 100644 index bad7745..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReplyBuilderFactory.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Sone - DefaultPostReplyBuilderFactory.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import net.pterodactylus.sone.database.PostProvider; -import net.pterodactylus.sone.database.PostReplyBuilder; -import net.pterodactylus.sone.database.PostReplyBuilderFactory; -import net.pterodactylus.sone.database.SoneProvider; - -import com.google.inject.Inject; - -/** - * {@link PostReplyBuilderFactory} that creates {@link PostReplyBuilderImpl}s. - * - * @author David ‘Bombe’ Roden - */ -public class DefaultPostReplyBuilderFactory implements PostReplyBuilderFactory { - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The post provider. */ - private final PostProvider postProvider; - - /** - * Creates a new default post reply builder factory. - * - * @param soneProvider - * The Sone provider - * @param postProvider - * The post provider - */ - @Inject - public DefaultPostReplyBuilderFactory(SoneProvider soneProvider, PostProvider postProvider) { - this.soneProvider = soneProvider; - this.postProvider = postProvider; - } - - /** - * {@inheritDoc} - */ - @Override - public PostReplyBuilder newPostReplyBuilder() { - return new PostReplyBuilderImpl(soneProvider, postProvider); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/IdOnlySone.java b/src/main/java/net/pterodactylus/sone/data/impl/IdOnlySone.java index 79766b5..e06e5a7 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/IdOnlySone.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/IdOnlySone.java @@ -23,8 +23,6 @@ import com.google.common.base.Objects; /** * {@link Sone} implementation that only stores the ID of a Sone and returns * {@code null}, {@code 0}, or empty collections where appropriate. - * - * @author David ‘Bombe’ Roden */ public class IdOnlySone implements Sone { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/ImageBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/ImageBuilderImpl.java index 4f4f26b..b62cc40 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/ImageBuilderImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/ImageBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Sone - ImageBuilderImpl.java - Copyright © 2013–2016 David Roden + * Sone - ImageBuilderImpl.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.database.ImageBuilder; /** * {@link ImageBuilder} implementation that creates {@link ImageImpl} objects. - * - * @author David Roden */ public class ImageBuilderImpl extends AbstractImageBuilder { diff --git a/src/main/java/net/pterodactylus/sone/data/impl/ImageImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/ImageImpl.java index 9f0fbbf..a54a8de 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/ImageImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/ImageImpl.java @@ -1,5 +1,5 @@ /* - * Sone - ImageImpl.java - Copyright © 2011–2016 David Roden + * Sone - ImageImpl.java - Copyright © 2011–2019 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 @@ -21,6 +21,7 @@ import static com.google.common.base.Optional.fromNullable; import static com.google.common.base.Optional.of; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +import static java.nio.charset.StandardCharsets.UTF_8; import java.util.UUID; @@ -34,8 +35,6 @@ import com.google.common.hash.Hashing; /** * Container for image metadata. - * - * @author David ‘Bombe’ Roden */ public class ImageImpl implements Image { @@ -248,11 +247,11 @@ public class ImageImpl implements Image { @Override public String getFingerprint() { Hasher hash = Hashing.sha256().newHasher(); - hash.putString("Image("); - hash.putString("ID(").putString(id).putString(")"); - hash.putString("Title(").putString(title).putString(")"); - hash.putString("Description(").putString(description).putString(")"); - hash.putString(")"); + hash.putString("Image(", UTF_8); + hash.putString("ID(", UTF_8).putString(id, UTF_8).putString(")", UTF_8); + hash.putString("Title(", UTF_8).putString(title, UTF_8).putString(")", UTF_8); + hash.putString("Description(", UTF_8).putString(description, UTF_8).putString(")", UTF_8); + hash.putString(")", UTF_8); return hash.hash().toString(); } diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java deleted file mode 100644 index 9fed167..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostBuilderImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Sone - PostBuilderImpl.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import java.util.UUID; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.database.PostBuilder; -import net.pterodactylus.sone.database.SoneProvider; - -/** - * {@link PostBuilder} implementation that creates {@link PostImpl} objects. - * - * @author David ‘Bombe’ Roden - */ -public class PostBuilderImpl extends AbstractPostBuilder { - - /** - * Creates a new post builder. - * - * @param soneProvider - * The Sone provider - */ - public PostBuilderImpl(SoneProvider soneProvider) { - super(soneProvider); - } - - /** - * {@inheritDoc} - */ - @Override - public Post build() { - validate(); - return new PostImpl(soneProvider, randomId ? UUID.randomUUID().toString() : id, senderId, recipientId, currentTime ? System.currentTimeMillis() : time, text); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java deleted file mode 100644 index 2b785f9..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Sone - PostImpl.java - Copyright © 2010–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import static com.google.common.base.Optional.fromNullable; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.database.SoneProvider; - -import com.google.common.base.Optional; - -/** - * A post is a short message that a user writes in his Sone to let other users - * know what is going on. - * - * @author David ‘Bombe’ Roden - */ -public class PostImpl implements Post { - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The GUID of the post. */ - private final String id; - - /** The ID of the owning Sone. */ - private final String soneId; - - /** The ID of the recipient Sone. */ - private final String recipientId; - - /** The time of the post (in milliseconds since Jan 1, 1970 UTC). */ - private final long time; - - /** The text of the post. */ - private final String text; - - /** Whether the post is known. */ - private volatile boolean known; - - /** - * Creates a new post. - * - * @param soneProvider - * The Sone provider - * @param id - * The ID of the post - * @param soneId - * The ID of the Sone this post belongs to - * @param recipientId - * The ID of the recipient of the post - * @param time - * The time of the post (in milliseconds since Jan 1, 1970 UTC) - * @param text - * The text of the post - */ - public PostImpl(SoneProvider soneProvider, String id, String soneId, String recipientId, long time, String text) { - this.soneProvider = soneProvider; - this.id = id; - this.soneId = soneId; - this.recipientId = recipientId; - this.time = time; - this.text = text; - } - - // - // ACCESSORS - // - - /** - * {@inheritDoc} - */ - @Override - public String getId() { - return id; - } - - @Override - public boolean isLoaded() { - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public Sone getSone() { - return soneProvider.getSone(soneId); - } - - /** - * {@inheritDocs} - */ - @Override - public Optional getRecipientId() { - return fromNullable(recipientId); - } - - /** - * {@inheritDoc} - */ - @Override - public Optional getRecipient() { - return fromNullable(soneProvider.getSone(recipientId)); - } - - /** - * {@inheritDoc} - */ - @Override - public long getTime() { - return time; - } - - /** - * {@inheritDoc} - */ - @Override - public String getText() { - return text; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isKnown() { - return known; - } - - /** - * {@inheritDoc} - */ - @Override - public PostImpl setKnown(boolean known) { - this.known = known; - return this; - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return id.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object object) { - if (!(object instanceof PostImpl)) { - return false; - } - PostImpl post = (PostImpl) object; - return post.id.equals(id); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return String.format("%s[id=%s,sone=%s,recipient=%s,time=%d,text=%s]", getClass().getName(), id, soneId, recipientId, time, text); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java deleted file mode 100644 index 7235bc9..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyBuilderImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Sone - PostReplyBuilderImpl.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import static com.google.common.base.Preconditions.checkState; - -import java.util.UUID; - -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.database.PostProvider; -import net.pterodactylus.sone.database.PostReplyBuilder; -import net.pterodactylus.sone.database.SoneProvider; - -/** - * {@link PostReplyBuilder} implementation that creates {@link PostReplyImpl} - * objects. - * - * @author David ‘Bombe’ Roden - */ -public class PostReplyBuilderImpl extends AbstractPostReplyBuilder { - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The post provider. */ - private final PostProvider postProvider; - - /** - * Creates a new post reply builder. - * - * @param soneProvider - * The Sone provider - * @param postProvider - * The post provider - */ - public PostReplyBuilderImpl(SoneProvider soneProvider, PostProvider postProvider) { - this.soneProvider = soneProvider; - this.postProvider = postProvider; - } - - /** - * {@inheritDoc} - */ - @Override - public PostReply build() { - checkState((randomId && (id == null)) || (!randomId && (id != null)), "either random ID nor custom ID must be set"); - checkState(senderId != null, "sender must not be null"); - checkState((currentTime && (time == 0)) || (!currentTime && (time >= 0)), "either current time or custom time must be set"); - checkState((text != null) && !text.trim().isEmpty(), "text must not be empty"); - checkState(postId != null, "post must not be null"); - - /* create new post reply. */ - return new PostReplyImpl(soneProvider, postProvider, randomId ? UUID.randomUUID().toString() : id, senderId, currentTime ? System.currentTimeMillis() : time, text, postId); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java deleted file mode 100644 index 3571172..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Sone - PostReplyImpl.java - Copyright © 2010–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import static com.google.common.base.Optional.fromNullable; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.database.PostProvider; -import net.pterodactylus.sone.database.SoneProvider; - -import com.google.common.base.Optional; - -/** - * Simple {@link PostReply} implementation. - * - * @author David ‘Bombe’ Roden - */ -public class PostReplyImpl extends ReplyImpl implements PostReply { - - /** The post provider. */ - private final PostProvider postProvider; - - /** The Post this reply refers to. */ - private final String postId; - - /** - * Creates a new reply. - * - * @param soneProvider - * The Sone provider - * @param postProvider - * The post provider - * @param id - * The ID of the reply - * @param soneId - * The ID of the Sone of the reply - * @param time - * The time of the reply - * @param text - * The text of the reply - * @param postId - * The ID of the post this reply refers to - */ - public PostReplyImpl(SoneProvider soneProvider, PostProvider postProvider, String id, String soneId, long time, String text, String postId) { - super(soneProvider, id, soneId, time, text); - this.postProvider = postProvider; - this.postId = postId; - } - - // - // ACCESSORS - // - - /** - * {@inheritDocs} - */ - @Override - public String getPostId() { - return postId; - } - - /** - * {@inheritDoc} - */ - @Override - public Optional getPost() { - return fromNullable(postProvider.getPost(postId)); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/ReplyImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/ReplyImpl.java deleted file mode 100644 index 372c80a..0000000 --- a/src/main/java/net/pterodactylus/sone/data/impl/ReplyImpl.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Sone - ReplyImpl.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.data.impl; - -import net.pterodactylus.sone.data.Reply; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.database.SoneProvider; - -/** - * Abstract base class for all replies. - * - * @param - * The type of the reply - * @author David ‘Bombe’ Roden - */ -public abstract class ReplyImpl> implements Reply { - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The ID of the reply. */ - private final String id; - - /** The Sone that created this reply. */ - private final String soneId; - - /** The time of the reply. */ - private final long time; - - /** The text of the reply. */ - private final String text; - - /** Whether the reply is known. */ - private volatile boolean known; - - /** - * Creates a new reply. - * - * @param soneProvider - * The Sone provider - * @param id - * The ID of the reply - * @param soneId - * The ID of the Sone of the reply - * @param time - * The time of the reply - * @param text - * The text of the reply - */ - protected ReplyImpl(SoneProvider soneProvider, String id, String soneId, long time, String text) { - this.soneProvider = soneProvider; - this.id = id; - this.soneId = soneId; - this.time = time; - this.text = text; - } - - /** - * {@inheritDoc} - */ - @Override - public String getId() { - return id; - } - - /** - * {@inheritDoc} - */ - @Override - public Sone getSone() { - return soneProvider.getSone(soneId); - } - - /** - * {@inheritDoc} - */ - @Override - public long getTime() { - return time; - } - - /** - * {@inheritDoc} - */ - @Override - public String getText() { - return text; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isKnown() { - return known; - } - - /** - * {@inheritDoc} - */ - @Override - @SuppressWarnings("unchecked") - public T setKnown(boolean known) { - this.known = known; - return (T) this; - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return id.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object object) { - if (!(object instanceof Reply)) { - return false; - } - Reply reply = (Reply) object; - return reply.getId().equals(id); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return String.format("%s[id=%s,sone=%s,time=%d,text=%s]", getClass().getName(), id, soneId, time, text); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/data/impl/SoneImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/SoneImpl.java index 0494607..3366448 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/SoneImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/SoneImpl.java @@ -1,5 +1,5 @@ /* - * Sone - SoneImpl.java - Copyright © 2010–2016 David Roden + * Sone - SoneImpl.java - Copyright © 2010–2019 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 @@ -19,6 +19,7 @@ package net.pterodactylus.sone.data.impl; import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.logging.Logger.getLogger; import java.net.MalformedURLException; @@ -56,8 +57,6 @@ import com.google.common.hash.Hashing; * {@link Sone} implementation. *

* Operations that modify the Sone need to synchronize on the Sone in question. - * - * @author David ‘Bombe’ Roden */ public class SoneImpl implements Sone { @@ -95,16 +94,16 @@ public class SoneImpl implements Sone { private volatile boolean known; /** All posts. */ - private final Set posts = new CopyOnWriteArraySet(); + private final Set posts = new CopyOnWriteArraySet<>(); /** All replies. */ - private final Set replies = new CopyOnWriteArraySet(); + private final Set replies = new CopyOnWriteArraySet<>(); /** The IDs of all liked posts. */ - private final Set likedPostIds = new CopyOnWriteArraySet(); + private final Set likedPostIds = new CopyOnWriteArraySet<>(); /** The IDs of all liked replies. */ - private final Set likedReplyIds = new CopyOnWriteArraySet(); + private final Set likedReplyIds = new CopyOnWriteArraySet<>(); /** The root album containing all albums. */ private final Album rootAlbum = new AlbumImpl(this); @@ -383,7 +382,7 @@ public class SoneImpl implements Sone { public List getPosts() { List sortedPosts; synchronized (this) { - sortedPosts = new ArrayList(posts); + sortedPosts = new ArrayList<>(posts); } Collections.sort(sortedPosts, Post.NEWEST_FIRST); return sortedPosts; @@ -636,46 +635,46 @@ public class SoneImpl implements Sone { @Override public synchronized String getFingerprint() { Hasher hash = Hashing.sha256().newHasher(); - hash.putString(profile.getFingerprint()); + hash.putString(profile.getFingerprint(), UTF_8); - hash.putString("Posts("); + hash.putString("Posts(", UTF_8); for (Post post : getPosts()) { - hash.putString("Post(").putString(post.getId()).putString(")"); + hash.putString("Post(", UTF_8).putString(post.getId(), UTF_8).putString(")", UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); - List replies = new ArrayList(getReplies()); + List replies = new ArrayList<>(getReplies()); Collections.sort(replies, Reply.TIME_COMPARATOR); - hash.putString("Replies("); + hash.putString("Replies(", UTF_8); for (PostReply reply : replies) { - hash.putString("Reply(").putString(reply.getId()).putString(")"); + hash.putString("Reply(", UTF_8).putString(reply.getId(), UTF_8).putString(")", UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); - List likedPostIds = new ArrayList(getLikedPostIds()); + List likedPostIds = new ArrayList<>(getLikedPostIds()); Collections.sort(likedPostIds); - hash.putString("LikedPosts("); + hash.putString("LikedPosts(", UTF_8); for (String likedPostId : likedPostIds) { - hash.putString("Post(").putString(likedPostId).putString(")"); + hash.putString("Post(", UTF_8).putString(likedPostId, UTF_8).putString(")", UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); - List likedReplyIds = new ArrayList(getLikedReplyIds()); + List likedReplyIds = new ArrayList<>(getLikedReplyIds()); Collections.sort(likedReplyIds); - hash.putString("LikedReplies("); + hash.putString("LikedReplies(", UTF_8); for (String likedReplyId : likedReplyIds) { - hash.putString("Reply(").putString(likedReplyId).putString(")"); + hash.putString("Reply(", UTF_8).putString(likedReplyId, UTF_8).putString(")", UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); - hash.putString("Albums("); + hash.putString("Albums(", UTF_8); for (Album album : rootAlbum.getAlbums()) { if (!Album.NOT_EMPTY.apply(album)) { continue; } - hash.putString(album.getFingerprint()); + hash.putString(album.getFingerprint(), UTF_8); } - hash.putString(")"); + hash.putString(")", UTF_8); return hash.hash().toString(); } diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt b/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt deleted file mode 100644 index ed441e0..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Sone - AlbumBuilder.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database - -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Sone - -/** - * Builder for [Album] objects. - */ -interface AlbumBuilder { - - fun randomId(): AlbumBuilder - fun withId(id: String): AlbumBuilder - - fun by(sone: Sone): AlbumBuilder - - fun build(): Album - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt b/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt deleted file mode 100644 index 6f854db..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Sone - AlbumBuilderFactory.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database - -/** - * Factory for [AlbumBuilder]s. - */ -interface AlbumBuilderFactory { - - fun newAlbumBuilder(): AlbumBuilder - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt b/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt deleted file mode 100644 index 69daa21..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Sone - AlbumDatabase.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database - -/** - * Combines an [AlbumProvider] and an [AlbumStore] into an album - * database. - */ -interface AlbumDatabase : AlbumProvider, AlbumBuilderFactory, AlbumStore diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt b/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt deleted file mode 100644 index c0b09e8..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Sone - AlbumProvider.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database - -import net.pterodactylus.sone.data.Album - -import com.google.common.base.Optional - -/** - * Interface for objects that can provide [Album]s by their ID. - */ -interface AlbumProvider { - - fun getAlbum(albumId: String): Album? - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt b/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt deleted file mode 100644 index e2a31c7..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Sone - AlbumStore.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database - -import net.pterodactylus.sone.data.Album - -/** - * Interface for a store of albums. - */ -interface AlbumStore { - - fun storeAlbum(album: Album) - fun removeAlbum(album: Album) - -} diff --git a/src/main/java/net/pterodactylus/sone/database/DatabaseException.java b/src/main/java/net/pterodactylus/sone/database/DatabaseException.java index bb98fec..9763ad6 100644 --- a/src/main/java/net/pterodactylus/sone/database/DatabaseException.java +++ b/src/main/java/net/pterodactylus/sone/database/DatabaseException.java @@ -1,5 +1,5 @@ /* - * Sone - DatabaseException.java - Copyright © 2013–2016 David Roden + * Sone - DatabaseException.java - Copyright © 2013–2019 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 @@ -19,8 +19,6 @@ package net.pterodactylus.sone.database; /** * Exception that signals a database error. - * - * @author David ‘Bombe’ Roden */ public class DatabaseException extends Exception { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/ConfigurationLoader.java b/src/main/java/net/pterodactylus/sone/database/memory/ConfigurationLoader.java index 0f55575..268f1a2 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/ConfigurationLoader.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/ConfigurationLoader.java @@ -3,17 +3,21 @@ package net.pterodactylus.sone.database.memory; import static java.util.logging.Level.WARNING; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.logging.Logger; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; /** * Helper class for interacting with a {@link Configuration}. - * - * @author David ‘Bombe’ Roden */ public class ConfigurationLoader { @@ -44,8 +48,52 @@ public class ConfigurationLoader { return loadIds("Bookmarks/Post"); } + @Nullable + public synchronized Long getSoneFollowingTime(@Nonnull String soneId) { + return loadSoneFollowingTimes().get(soneId); + } + + public synchronized void removeSoneFollowingTime(@Nonnull String soneId) { + Map soneFollowingTimes = loadSoneFollowingTimes(); + soneFollowingTimes.remove(soneId); + storeSoneFollowingTimes(soneFollowingTimes); + } + + public synchronized void setSoneFollowingTime(@Nonnull String soneId, long time) { + Map soneFollowingTimes = loadSoneFollowingTimes(); + soneFollowingTimes.put(soneId, time); + storeSoneFollowingTimes(soneFollowingTimes); + } + + private synchronized Map loadSoneFollowingTimes() { + Map soneFollowingTimes = new HashMap<>(); + int soneCounter = 0; + while (true) { + String soneId = configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").getValue(null); + if (soneId == null) { + break; + } + soneFollowingTimes.put(soneId, configuration.getLongValue("SoneFollowingTimes/" + soneCounter++ + "/Time").getValue(null)); + } + return soneFollowingTimes; + } + + private synchronized void storeSoneFollowingTimes(Map soneFollowingTimes) { + int soneCounter = 0; + try { + for (Entry soneFollowingTime : soneFollowingTimes.entrySet()) { + configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(soneFollowingTime.getKey()); + configuration.getLongValue("SoneFollowingTimes/" + soneCounter + "/Time").setValue(soneFollowingTime.getValue()); + ++soneCounter; + } + configuration.getStringValue("SoneFollowingTimes/" + soneCounter + "/Sone").setValue(null); + } catch (ConfigurationException ce1) { + logger.log(WARNING, "Could not save Sone following times!", ce1); + } + } + private Set loadIds(String prefix) { - Set ids = new HashSet(); + Set ids = new HashSet<>(); int idCounter = 0; while (true) { String id = configuration diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java index 4c4bc3f..1a4e119 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java @@ -16,15 +16,13 @@ import com.google.common.base.Function; /** * Memory-based {@link BookmarkDatabase} implementation. - * - * @author David ‘Bombe’ Roden */ public class MemoryBookmarkDatabase implements BookmarkDatabase { private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final MemoryDatabase memoryDatabase; private final ConfigurationLoader configurationLoader; - private final Set bookmarkedPosts = new HashSet(); + private final Set bookmarkedPosts = new HashSet<>(); public MemoryBookmarkDatabase(MemoryDatabase memoryDatabase, ConfigurationLoader configurationLoader) { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java deleted file mode 100644 index 5e5021c..0000000 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ /dev/null @@ -1,762 +0,0 @@ -/* - * Sone - MemoryDatabase.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database.memory; - -import static com.google.common.base.Optional.fromNullable; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Predicates.not; -import static com.google.common.collect.FluentIterable.from; -import static net.pterodactylus.sone.data.Reply.TIME_COMPARATOR; -import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER; -import static net.pterodactylus.sone.data.Sone.toAllAlbums; -import static net.pterodactylus.sone.data.Sone.toAllImages; - -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -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.Sone; -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.database.SoneBuilder; -import net.pterodactylus.sone.database.SoneProvider; -import net.pterodactylus.util.config.Configuration; -import net.pterodactylus.util.config.ConfigurationException; - -import com.google.common.base.Predicate; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.SortedSetMultimap; -import com.google.common.collect.TreeMultimap; -import com.google.common.util.concurrent.AbstractService; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import kotlin.jvm.functions.Function1; - -/** - * Memory-based {@link PostDatabase} implementation. - * - * @author David ‘Bombe’ Roden - */ -@Singleton -public class MemoryDatabase extends AbstractService implements Database { - - /** The lock. */ - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The configuration. */ - private final Configuration configuration; - private final ConfigurationLoader configurationLoader; - - private final Map allSones = new HashMap(); - - /** All posts by their ID. */ - private final Map allPosts = new HashMap(); - - /** All posts by their Sones. */ - private final Multimap sonePosts = HashMultimap.create(); - - /** Whether posts are known. */ - private final Set knownPosts = new HashSet(); - - /** All post replies by their ID. */ - private final Map allPostReplies = new HashMap(); - - /** Replies sorted by Sone. */ - private final SortedSetMultimap sonePostReplies = TreeMultimap.create(new Comparator() { - - @Override - public int compare(String leftString, String rightString) { - return leftString.compareTo(rightString); - } - }, TIME_COMPARATOR); - - /** Whether post replies are known. */ - private final Set knownPostReplies = new HashSet(); - - private final Map allAlbums = new HashMap(); - private final Multimap soneAlbums = HashMultimap.create(); - - private final Map allImages = new HashMap(); - private final Multimap soneImages = HashMultimap.create(); - - private final MemoryBookmarkDatabase memoryBookmarkDatabase; - private final MemoryFriendDatabase memoryFriendDatabase; - - /** - * Creates a new memory database. - * - * @param soneProvider - * The Sone provider - * @param configuration - * The configuration for loading and saving elements - */ - @Inject - public MemoryDatabase(SoneProvider soneProvider, Configuration configuration) { - this.soneProvider = soneProvider; - this.configuration = configuration; - this.configurationLoader = new ConfigurationLoader(configuration); - memoryBookmarkDatabase = - new MemoryBookmarkDatabase(this, configurationLoader); - memoryFriendDatabase = new MemoryFriendDatabase(configurationLoader); - } - - // - // DATABASE METHODS - // - - /** - * Saves the database. - * - * @throws DatabaseException - * if an error occurs while saving - */ - @Override - public void save() throws DatabaseException { - saveKnownPosts(); - saveKnownPostReplies(); - } - - // - // SERVICE METHODS - // - - /** {@inheritDocs} */ - @Override - protected void doStart() { - memoryBookmarkDatabase.start(); - loadKnownPosts(); - loadKnownPostReplies(); - notifyStarted(); - } - - /** {@inheritDocs} */ - @Override - protected void doStop() { - try { - memoryBookmarkDatabase.stop(); - save(); - notifyStopped(); - } catch (DatabaseException de1) { - notifyFailed(de1); - } - } - - @Override - public SoneBuilder newSoneBuilder() { - return new MemorySoneBuilder(this); - } - - @Override - public void storeSone(Sone sone) { - lock.writeLock().lock(); - try { - removeSone(sone); - - allSones.put(sone.getId(), sone); - sonePosts.putAll(sone.getId(), sone.getPosts()); - for (Post post : sone.getPosts()) { - allPosts.put(post.getId(), post); - } - sonePostReplies.putAll(sone.getId(), sone.getReplies()); - for (PostReply postReply : sone.getReplies()) { - allPostReplies.put(postReply.getId(), postReply); - } - soneAlbums.putAll(sone.getId(), toAllAlbums.apply(sone)); - for (Album album : toAllAlbums.apply(sone)) { - allAlbums.put(album.getId(), album); - } - soneImages.putAll(sone.getId(), toAllImages.apply(sone)); - for (Image image : toAllImages.apply(sone)) { - allImages.put(image.getId(), image); - } - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public void removeSone(Sone sone) { - lock.writeLock().lock(); - try { - allSones.remove(sone.getId()); - Collection removedPosts = sonePosts.removeAll(sone.getId()); - for (Post removedPost : removedPosts) { - allPosts.remove(removedPost.getId()); - } - Collection removedPostReplies = - sonePostReplies.removeAll(sone.getId()); - for (PostReply removedPostReply : removedPostReplies) { - allPostReplies.remove(removedPostReply.getId()); - } - Collection removedAlbums = - soneAlbums.removeAll(sone.getId()); - for (Album removedAlbum : removedAlbums) { - allAlbums.remove(removedAlbum.getId()); - } - Collection removedImages = - soneImages.removeAll(sone.getId()); - for (Image removedImage : removedImages) { - allImages.remove(removedImage.getId()); - } - } finally { - lock.writeLock().unlock(); - } - } - - @Nonnull - @Override - public Function1 getSoneLoader() { - return new Function1() { - @Override - public Sone invoke(String soneId) { - return getSone(soneId); - } - }; - } - - @Override - public Sone getSone(String soneId) { - lock.readLock().lock(); - try { - return allSones.get(soneId); - } finally { - lock.readLock().unlock(); - } - } - - @Override - public Collection getSones() { - lock.readLock().lock(); - try { - return new HashSet(allSones.values()); - } finally { - lock.readLock().unlock(); - } - } - - @Override - public Collection getLocalSones() { - lock.readLock().lock(); - try { - return from(allSones.values()).filter(LOCAL_SONE_FILTER).toSet(); - } finally { - lock.readLock().unlock(); - } - } - - @Override - public Collection getRemoteSones() { - lock.readLock().lock(); - try { - return from(allSones.values()) - .filter(not(LOCAL_SONE_FILTER)) .toSet(); - } finally { - lock.readLock().unlock(); - } - } - - @Override - public Collection getFriends(Sone localSone) { - if (!localSone.isLocal()) { - return Collections.emptySet(); - } - return memoryFriendDatabase.getFriends(localSone.getId()); - } - - @Override - public boolean isFriend(Sone localSone, String friendSoneId) { - if (!localSone.isLocal()) { - return false; - } - return memoryFriendDatabase.isFriend(localSone.getId(), friendSoneId); - } - - @Override - public void addFriend(Sone localSone, String friendSoneId) { - if (!localSone.isLocal()) { - return; - } - memoryFriendDatabase.addFriend(localSone.getId(), friendSoneId); - } - - @Override - public void removeFriend(Sone localSone, String friendSoneId) { - if (!localSone.isLocal()) { - return; - } - memoryFriendDatabase.removeFriend(localSone.getId(), friendSoneId); - } - - // - // POSTPROVIDER METHODS - // - - @Nullable - @Override - public Post getPost(@Nonnull String postId) { - lock.readLock().lock(); - try { - return allPosts.get(postId); - } finally { - lock.readLock().unlock(); - } - } - - /** {@inheritDocs} */ - @Override - public Collection getPosts(String soneId) { - return new HashSet(getPostsFrom(soneId)); - } - - /** {@inheritDocs} */ - @Override - public Collection getDirectedPosts(final String recipientId) { - lock.readLock().lock(); - try { - return from(sonePosts.values()).filter(new Predicate() { - @Override - public boolean apply(Post post) { - return post.getRecipientId().asSet().contains(recipientId); - } - }).toSet(); - } finally { - lock.readLock().unlock(); - } - } - - // - // POSTBUILDERFACTORY METHODS - // - - /** {@inheritDocs} */ - @Override - public PostBuilder newPostBuilder() { - return new MemoryPostBuilder(this, soneProvider); - } - - // - // POSTSTORE METHODS - // - - /** {@inheritDocs} */ - @Override - public void storePost(Post post) { - checkNotNull(post, "post must not be null"); - lock.writeLock().lock(); - try { - allPosts.put(post.getId(), post); - getPostsFrom(post.getSone().getId()).add(post); - } finally { - lock.writeLock().unlock(); - } - } - - /** {@inheritDocs} */ - @Override - public void removePost(Post post) { - checkNotNull(post, "post must not be null"); - lock.writeLock().lock(); - try { - allPosts.remove(post.getId()); - getPostsFrom(post.getSone().getId()).remove(post); - post.getSone().removePost(post); - } finally { - lock.writeLock().unlock(); - } - } - - // - // POSTREPLYPROVIDER METHODS - // - - @Nullable - @Override - public PostReply getPostReply(String id) { - lock.readLock().lock(); - try { - return allPostReplies.get(id); - } finally { - lock.readLock().unlock(); - } - } - - /** {@inheritDocs} */ - @Override - public List getReplies(final String postId) { - lock.readLock().lock(); - try { - return from(allPostReplies.values()) - .filter(new Predicate() { - @Override - public boolean apply(PostReply postReply) { - return postReply.getPostId().equals(postId); - } - }).toSortedList(TIME_COMPARATOR); - } finally { - lock.readLock().unlock(); - } - } - - // - // POSTREPLYBUILDERFACTORY METHODS - // - - /** {@inheritDocs} */ - @Override - public PostReplyBuilder newPostReplyBuilder() { - return new MemoryPostReplyBuilder(this, soneProvider); - } - - // - // POSTREPLYSTORE METHODS - // - - /** {@inheritDocs} */ - @Override - public void storePostReply(PostReply postReply) { - lock.writeLock().lock(); - try { - allPostReplies.put(postReply.getId(), postReply); - } finally { - lock.writeLock().unlock(); - } - } - - /** {@inheritDocs} */ - @Override - public void removePostReply(PostReply postReply) { - lock.writeLock().lock(); - try { - allPostReplies.remove(postReply.getId()); - } finally { - lock.writeLock().unlock(); - } - } - - // - // ALBUMPROVDER METHODS - // - - @Nullable - @Override - public Album getAlbum(@Nonnull String albumId) { - lock.readLock().lock(); - try { - return allAlbums.get(albumId); - } finally { - lock.readLock().unlock(); - } - } - - // - // ALBUMBUILDERFACTORY METHODS - // - - @Override - public AlbumBuilder newAlbumBuilder() { - return new AlbumBuilderImpl(); - } - - // - // ALBUMSTORE METHODS - // - - @Override - public void storeAlbum(Album album) { - lock.writeLock().lock(); - try { - allAlbums.put(album.getId(), album); - soneAlbums.put(album.getSone().getId(), album); - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public void removeAlbum(Album album) { - lock.writeLock().lock(); - try { - allAlbums.remove(album.getId()); - soneAlbums.remove(album.getSone().getId(), album); - } finally { - lock.writeLock().unlock(); - } - } - - // - // IMAGEPROVIDER METHODS - // - - @Nullable - @Override - public Image getImage(@Nonnull String imageId) { - lock.readLock().lock(); - try { - return allImages.get(imageId); - } finally { - lock.readLock().unlock(); - } - } - - // - // IMAGEBUILDERFACTORY METHODS - // - - @Override - public ImageBuilder newImageBuilder() { - return new ImageBuilderImpl(); - } - - // - // IMAGESTORE METHODS - // - - @Override - public void storeImage(Image image) { - lock.writeLock().lock(); - try { - allImages.put(image.getId(), image); - soneImages.put(image.getSone().getId(), image); - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public void removeImage(Image image) { - lock.writeLock().lock(); - try { - allImages.remove(image.getId()); - soneImages.remove(image.getSone().getId(), image); - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public void bookmarkPost(Post post) { - memoryBookmarkDatabase.bookmarkPost(post); - } - - @Override - public void unbookmarkPost(Post post) { - memoryBookmarkDatabase.unbookmarkPost(post); - } - - @Override - public boolean isPostBookmarked(Post post) { - return memoryBookmarkDatabase.isPostBookmarked(post); - } - - @Override - public Set getBookmarkedPosts() { - return memoryBookmarkDatabase.getBookmarkedPosts(); - } - - // - // PACKAGE-PRIVATE METHODS - // - - /** - * Returns whether the given post is known. - * - * @param post - * The post - * @return {@code true} if the post is known, {@code false} otherwise - */ - boolean isPostKnown(Post post) { - lock.readLock().lock(); - try { - return knownPosts.contains(post.getId()); - } finally { - lock.readLock().unlock(); - } - } - - /** - * Sets whether the given post is known. - * - * @param post - * The post - * @param known - * {@code true} if the post is known, {@code false} otherwise - */ - void setPostKnown(Post post, boolean known) { - lock.writeLock().lock(); - try { - if (known) { - knownPosts.add(post.getId()); - } else { - knownPosts.remove(post.getId()); - } - } finally { - lock.writeLock().unlock(); - } - } - - /** - * Returns whether the given post reply is known. - * - * @param postReply - * The post reply - * @return {@code true} if the given post reply is known, {@code false} - * otherwise - */ - boolean isPostReplyKnown(PostReply postReply) { - lock.readLock().lock(); - try { - return knownPostReplies.contains(postReply.getId()); - } finally { - lock.readLock().unlock(); - } - } - - /** - * Sets whether the given post reply is known. - * - * @param postReply - * The post reply - * @param known - * {@code true} if the post reply is known, {@code false} otherwise - */ - void setPostReplyKnown(PostReply postReply, boolean known) { - lock.writeLock().lock(); - try { - if (known) { - knownPostReplies.add(postReply.getId()); - } else { - knownPostReplies.remove(postReply.getId()); - } - } finally { - lock.writeLock().unlock(); - } - } - - // - // PRIVATE METHODS - // - - /** - * Gets all posts for the given Sone, creating a new collection if there is - * none yet. - * - * @param soneId - * The ID of the Sone to get the posts for - * @return All posts - */ - private Collection getPostsFrom(String soneId) { - lock.readLock().lock(); - try { - return sonePosts.get(soneId); - } finally { - lock.readLock().unlock(); - } - } - - /** Loads the known posts. */ - private void loadKnownPosts() { - Set knownPosts = configurationLoader.loadKnownPosts(); - lock.writeLock().lock(); - try { - this.knownPosts.clear(); - this.knownPosts.addAll(knownPosts); - } finally { - lock.writeLock().unlock(); - } - } - - /** - * Saves the known posts to the configuration. - * - * @throws DatabaseException - * if a configuration error occurs - */ - private void saveKnownPosts() throws DatabaseException { - lock.readLock().lock(); - try { - int postCounter = 0; - for (String knownPostId : knownPosts) { - configuration.getStringValue("KnownPosts/" + postCounter++ + "/ID").setValue(knownPostId); - } - configuration.getStringValue("KnownPosts/" + postCounter + "/ID").setValue(null); - } catch (ConfigurationException ce1) { - throw new DatabaseException("Could not save database.", ce1); - } finally { - lock.readLock().unlock(); - } - } - - /** Loads the known post replies. */ - private void loadKnownPostReplies() { - Set knownPostReplies = configurationLoader.loadKnownPostReplies(); - lock.writeLock().lock(); - try { - this.knownPostReplies.clear(); - this.knownPostReplies.addAll(knownPostReplies); - } finally { - lock.writeLock().unlock(); - } - } - - /** - * Saves the known post replies to the configuration. - * - * @throws DatabaseException - * if a configuration error occurs - */ - private void saveKnownPostReplies() throws DatabaseException { - lock.readLock().lock(); - try { - int replyCounter = 0; - for (String knownReplyId : knownPostReplies) { - configuration.getStringValue("KnownReplies/" + replyCounter++ + "/ID").setValue(knownReplyId); - } - configuration.getStringValue("KnownReplies/" + replyCounter + "/ID").setValue(null); - } catch (ConfigurationException ce1) { - throw new DatabaseException("Could not save database.", ce1); - } finally { - lock.readLock().unlock(); - } - } - -} diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt new file mode 100644 index 0000000..6fce7e0 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.kt @@ -0,0 +1,345 @@ +/* + * Sone - MemoryDatabase.kt - Copyright © 2013–2019 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 . + */ + +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.AbstractService +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.unit +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() + private val allPosts = mutableMapOf() + private val sonePosts: Multimap = HashMultimap.create() + private val knownPosts = mutableSetOf() + private val allPostReplies = mutableMapOf() + private val sonePostReplies: Multimap = TreeMultimap.create(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, TIME_COMPARATOR) + private val knownPostReplies = mutableSetOf() + private val allAlbums = mutableMapOf() + private val soneAlbums: Multimap = HashMultimap.create() + private val allImages = mutableMapOf() + private val soneImages: Multimap = HashMultimap.create() + private val memoryBookmarkDatabase = MemoryBookmarkDatabase(this, configurationLoader) + private val memoryFriendDatabase = MemoryFriendDatabase(configurationLoader) + + 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() { + 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 = + 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 = + 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() = + 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() = + 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/database/memory/MemoryFriendDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryFriendDatabase.java index 0be8738..6661be0 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryFriendDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryFriendDatabase.java @@ -4,13 +4,14 @@ import java.util.Collection; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; /** * In-memory implementation of friend-related functionality. - * - * @author David ‘Bombe’ Roden */ class MemoryFriendDatabase { @@ -48,6 +49,9 @@ class MemoryFriendDatabase { try { if (soneFriends.put(localSoneId, friendSoneId)) { configurationLoader.saveFriends(localSoneId, soneFriends.get(localSoneId)); + if (configurationLoader.getSoneFollowingTime(friendSoneId) == null) { + configurationLoader.setSoneFollowingTime(friendSoneId, System.currentTimeMillis()); + } } } finally { lock.writeLock().unlock(); @@ -60,12 +64,24 @@ class MemoryFriendDatabase { try { if (soneFriends.remove(localSoneId, friendSoneId)) { configurationLoader.saveFriends(localSoneId, soneFriends.get(localSoneId)); + boolean unfollowedSoneStillFollowed = false; + for (String soneId : soneFriends.keys()) { + unfollowedSoneStillFollowed |= getFriends(soneId).contains(friendSoneId); + } + if (!unfollowedSoneStillFollowed) { + configurationLoader.removeSoneFollowingTime(friendSoneId); + } } } finally { lock.writeLock().unlock(); } } + @Nullable + Long getFollowingTime(@Nonnull String soneId) { + return configurationLoader.getSoneFollowingTime(soneId); + } + private void loadFriends(String localSoneId) { lock.writeLock().lock(); try { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java index 724c627..30fc2b0 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java @@ -1,5 +1,5 @@ /* - * Sone - MemoryPost.java - Copyright © 2010–2016 David Roden + * Sone - MemoryPost.java - Copyright © 2010–2019 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 @@ -30,8 +30,6 @@ import com.google.common.base.Optional; /** * A post is a short message that a user writes in his Sone to let other users * know what is going on. - * - * @author David ‘Bombe’ Roden */ class MemoryPost implements Post { @@ -122,7 +120,7 @@ class MemoryPost implements Post { */ @Override public Optional getRecipient() { - return fromNullable(soneProvider.getSone(recipientId)); + return recipientId == null ? Optional.absent() : fromNullable(soneProvider.getSone(recipientId)); } /** diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostBuilder.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostBuilder.java index 7125167..dea3449 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostBuilder.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - MemoryPostBuilder.java - Copyright © 2013–2016 David Roden + * Sone - MemoryPostBuilder.java - Copyright © 2013–2019 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 @@ -26,8 +26,6 @@ import net.pterodactylus.sone.database.SoneProvider; /** * {@link PostBuilder} implementation that creates a {@link MemoryPost}. - * - * @author David ‘Bombe’ Roden */ class MemoryPostBuilder extends AbstractPostBuilder { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java index 687c28a..40f0775 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java @@ -1,5 +1,5 @@ /* - * Sone - MemoryPostReply.java - Copyright © 2013–2016 David Roden + * Sone - MemoryPostReply.java - Copyright © 2013–2019 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 @@ -28,8 +28,6 @@ import com.google.common.base.Optional; /** * Memory-based {@link PostReply} implementation. - * - * @author David ‘Bombe’ Roden */ class MemoryPostReply implements PostReply { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReplyBuilder.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReplyBuilder.java index 59e098c..3bcfe33 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReplyBuilder.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReplyBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - MemoryPostReplyBuilder.java - Copyright © 2013–2016 David Roden + * Sone - MemoryPostReplyBuilder.java - Copyright © 2013–2019 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 @@ -27,8 +27,6 @@ import net.pterodactylus.sone.database.SoneProvider; /** * {@link PostReplyBuilder} implementation that creates {@link MemoryPostReply} * objects. - * - * @author David ‘Bombe’ Roden */ class MemoryPostReplyBuilder extends AbstractPostReplyBuilder { diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemorySoneBuilder.java b/src/main/java/net/pterodactylus/sone/database/memory/MemorySoneBuilder.java index 49531a1..14997dd 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemorySoneBuilder.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemorySoneBuilder.java @@ -7,8 +7,6 @@ import net.pterodactylus.sone.database.Database; /** * Memory-based {@link AbstractSoneBuilder} implementation. - * - * @author David ‘Bombe’ Roden */ public class MemorySoneBuilder extends AbstractSoneBuilder { diff --git a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java deleted file mode 100644 index 9942af7..0000000 --- a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Sone - AbstractSoneCommand.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.fcp; - -import java.util.Collection; -import java.util.List; - -import net.pterodactylus.sone.core.Core; -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Profile; -import net.pterodactylus.sone.data.Profile.Field; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder; -import net.pterodactylus.sone.freenet.fcp.AbstractCommand; -import net.pterodactylus.sone.freenet.fcp.Command; -import net.pterodactylus.sone.freenet.fcp.FcpException; -import net.pterodactylus.sone.template.SoneAccessor; - -import freenet.node.FSParseException; -import freenet.support.SimpleFieldSet; - -import com.google.common.base.Optional; - -/** - * Abstract base implementation of a {@link Command} with Sone-related helper - * methods. - * - * @author David ‘Bombe’ Roden - */ -public abstract class AbstractSoneCommand extends AbstractCommand { - - /** The Sone core. */ - private final Core core; - - /** Whether this command needs write access. */ - private final boolean writeAccess; - - /** - * Creates a new abstract Sone FCP command. - * - * @param core - * The Sone core - */ - protected AbstractSoneCommand(Core core) { - this(core, false); - } - - /** - * Creates a new abstract Sone FCP command. - * - * @param core - * The Sone core - * @param writeAccess - * {@code true} if this command requires write access, - * {@code false} otherwise - */ - protected AbstractSoneCommand(Core core, boolean writeAccess) { - this.core = core; - this.writeAccess = writeAccess; - } - - // - // ACCESSORS - // - - /** - * Returns the Sone core. - * - * @return The Sone core - */ - protected Core getCore() { - return core; - } - - /** - * Returns whether this command requires write access. - * - * @return {@code true} if this command require write access, {@code false} - * otherwise - */ - public boolean requiresWriteAccess() { - return writeAccess; - } - - // - // PROTECTED METHODS - // - - /** - * Encodes text in a way that makes it possible for the text to be stored in - * a {@link SimpleFieldSet}. Backslashes, CR, and LF are prepended with a - * backslash. - * - * @param text - * The text to encode - * @return The encoded text - */ - protected static String encodeString(String text) { - return text.replaceAll("\\\\", "\\\\\\\\").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r"); - } - - /** - * Returns a Sone whose ID is a parameter in the given simple field set. - * - * @param simpleFieldSet - * The simple field set containing the ID of the Sone - * @param parameterName - * The name under which the Sone ID is stored in the simple field - * set - * @param localOnly - * {@code true} to only return local Sones, {@code false} to - * return any Sones - * @return The Sone - * @throws FcpException - * if there is no Sone ID stored under the given parameter name, - * or if the Sone ID is invalid - */ - protected Sone getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly) throws FcpException { - return getSone(simpleFieldSet, parameterName, localOnly, true).get(); - } - - /** - * Returns a Sone whose ID is a parameter in the given simple field set. - * - * @param simpleFieldSet - * The simple field set containing the ID of the Sone - * @param parameterName - * The name under which the Sone ID is stored in the simple field - * set - * @param localOnly - * {@code true} to only return local Sones, {@code false} to - * return any Sones - * @param mandatory - * {@code true} if a valid Sone ID is required, {@code false} - * otherwise - * @return The Sone, or {@code null} if {@code mandatory} is {@code false} - * and the Sone ID is invalid - * @throws FcpException - * if there is no Sone ID stored under the given parameter name, - * or if {@code mandatory} is {@code true} and the Sone ID is - * invalid - */ - protected Optional getSone(SimpleFieldSet simpleFieldSet, String parameterName, boolean localOnly, boolean mandatory) throws FcpException { - String soneId = simpleFieldSet.get(parameterName); - if (mandatory && (soneId == null)) { - throw new FcpException("Could not load Sone ID from “" + parameterName + "”."); - } - Sone sone = core.getSone(soneId); - if ((mandatory && (sone == null)) || ((sone != null) && localOnly && !sone.isLocal())) { - throw new FcpException("Could not load Sone from “" + soneId + "”."); - } - return Optional.fromNullable(sone); - } - - /** - * Returns a post whose ID is a parameter in the given simple field set. - * - * @param simpleFieldSet - * The simple field set containing the ID of the post - * @param parameterName - * The name under which the post ID is stored in the simple field - * set - * @return The post - * @throws FcpException - * if there is no post ID stored under the given parameter name, - * or if the post ID is invalid - */ - protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { - try { - String postId = simpleFieldSet.getString(parameterName); - Post post = core.getPost(postId); - if (post == null) { - throw new FcpException("Could not load post from “" + postId + "”."); - } - return post; - } catch (FSParseException fspe1) { - throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1); - } - } - - /** - * Returns a reply whose ID is a parameter in the given simple field set. - * - * @param simpleFieldSet - * The simple field set containing the ID of the reply - * @param parameterName - * The name under which the reply ID is stored in the simple - * field set - * @return The reply - * @throws FcpException - * if there is no reply ID stored under the given parameter - * name, or if the reply ID is invalid - */ - protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { - try { - String replyId = simpleFieldSet.getString(parameterName); - PostReply reply = core.getPostReply(replyId); - if (reply == null) { - throw new FcpException("Could not load reply from “" + replyId + "”."); - } - return reply; - } catch (FSParseException fspe1) { - throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1); - } - } - - /** - * Creates a simple field set from the given Sone, including {@link Profile} - * information. - * - * @param sone - * The Sone to encode - * @param prefix - * The prefix for the field names (may be empty but not {@code - * null}) - * @param localSone - * An optional local Sone that is used for Sone-specific data, - * such as if the Sone is followed by the local Sone - * @return The simple field set containing the given Sone - */ - protected static SimpleFieldSet encodeSone(Sone sone, String prefix, Optional localSone) { - SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder(); - - soneBuilder.put(prefix + "ID", sone.getId()); - soneBuilder.put(prefix + "Name", sone.getName()); - soneBuilder.put(prefix + "NiceName", SoneAccessor.getNiceName(sone)); - soneBuilder.put(prefix + "LastUpdated", sone.getTime()); - if (localSone.isPresent()) { - soneBuilder.put(prefix + "Followed", String.valueOf(localSone.get().hasFriend(sone.getId()))); - } - Profile profile = sone.getProfile(); - soneBuilder.put(prefix + "Field.Count", profile.getFields().size()); - int fieldIndex = 0; - for (Field field : profile.getFields()) { - soneBuilder.put(prefix + "Field." + fieldIndex + ".Name", field.getName()); - soneBuilder.put(prefix + "Field." + fieldIndex + ".Value", field.getValue()); - ++fieldIndex; - } - - return soneBuilder.get(); - } - - /** - * Creates a simple field set from the given collection of Sones. - * - * @param sones - * The Sones to encode - * @param prefix - * The prefix for the field names (may be empty but not - * {@code null}) - * @return The simple field set containing the given Sones - */ - protected static SimpleFieldSet encodeSones(Collection sones, String prefix) { - SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder(); - - int soneIndex = 0; - soneBuilder.put(prefix + "Count", sones.size()); - for (Sone sone : sones) { - String sonePrefix = prefix + soneIndex++ + "."; - soneBuilder.put(encodeSone(sone, sonePrefix, Optional.absent())); - } - - return soneBuilder.get(); - } - - /** - * Creates a simple field set from the given post. - * - * @param post - * The post to encode - * @param prefix - * The prefix for the field names (may be empty but not - * {@code null}) - * @param includeReplies - * {@code true} to include replies, {@code false} to not include - * replies - * @return The simple field set containing the post - */ - protected SimpleFieldSet encodePost(Post post, String prefix, boolean includeReplies) { - SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder(); - - postBuilder.put(prefix + "ID", post.getId()); - postBuilder.put(prefix + "Sone", post.getSone().getId()); - if (post.getRecipientId().isPresent()) { - postBuilder.put(prefix + "Recipient", post.getRecipientId().get()); - } - postBuilder.put(prefix + "Time", post.getTime()); - postBuilder.put(prefix + "Text", encodeString(post.getText())); - postBuilder.put(encodeLikes(core.getLikes(post), prefix + "Likes.")); - - if (includeReplies) { - List replies = core.getReplies(post.getId()); - postBuilder.put(encodeReplies(replies, prefix)); - } - - return postBuilder.get(); - } - - /** - * Creates a simple field set from the given collection of posts. - * - * @param posts - * The posts to encode - * @param prefix - * The prefix for the field names (may be empty but not - * {@code null}) - * @param includeReplies - * {@code true} to include the replies, {@code false} to not - * include the replies - * @return The simple field set containing the posts - */ - protected SimpleFieldSet encodePosts(Collection posts, String prefix, boolean includeReplies) { - SimpleFieldSetBuilder postBuilder = new SimpleFieldSetBuilder(); - - int postIndex = 0; - postBuilder.put(prefix + "Count", posts.size()); - for (Post post : posts) { - String postPrefix = prefix + postIndex++; - postBuilder.put(encodePost(post, postPrefix + ".", includeReplies)); - } - - return postBuilder.get(); - } - - /** - * Creates a simple field set from the given collection of replies. - * - * @param replies - * The replies to encode - * @param prefix - * The prefix for the field names (may be empty, but not - * {@code null}) - * @return The simple field set containing the replies - */ - protected SimpleFieldSet encodeReplies(Collection replies, String prefix) { - SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder(); - - int replyIndex = 0; - replyBuilder.put(prefix + "Replies.Count", replies.size()); - for (PostReply reply : replies) { - String replyPrefix = prefix + "Replies." + replyIndex++ + "."; - replyBuilder.put(replyPrefix + "ID", reply.getId()); - replyBuilder.put(replyPrefix + "Sone", reply.getSone().getId()); - replyBuilder.put(replyPrefix + "Time", reply.getTime()); - replyBuilder.put(replyPrefix + "Text", encodeString(reply.getText())); - replyBuilder.put(encodeLikes(core.getLikes(reply), replyPrefix + "Likes.")); - } - - return replyBuilder.get(); - } - - /** - * Creates a simple field set from the given collection of Sones that like - * an element. - * - * @param likes - * The liking Sones - * @param prefix - * The prefix for the field names (may be empty but not - * {@code null}) - * @return The simple field set containing the likes - */ - protected static SimpleFieldSet encodeLikes(Collection likes, String prefix) { - SimpleFieldSetBuilder likesBuilder = new SimpleFieldSetBuilder(); - - int likeIndex = 0; - likesBuilder.put(prefix + "Count", likes.size()); - for (Sone sone : likes) { - String sonePrefix = prefix + likeIndex++ + "."; - likesBuilder.put(sonePrefix + "ID", sone.getId()); - } - - return likesBuilder.get(); - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return getClass().getName() + "[writeAccess=" + writeAccess + "]"; - } - -} diff --git a/src/main/java/net/pterodactylus/sone/fcp/CreatePostCommand.java b/src/main/java/net/pterodactylus/sone/fcp/CreatePostCommand.java index a3f709e..2c8456d 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/CreatePostCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/CreatePostCommand.java @@ -1,5 +1,5 @@ /* - * Sone - CreatePostCommand.java - Copyright © 2011–2016 David Roden + * Sone - CreatePostCommand.java - Copyright © 2011–2019 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 @@ -30,7 +30,6 @@ import freenet.support.SimpleFieldSet; * FCP command that creates a new {@link Post}. * * @see Core#createPost(Sone, Optional, String) - * @author David ‘Bombe’ Roden */ public class CreatePostCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java index d268a07..9f17940 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java @@ -1,5 +1,5 @@ /* - * Sone - CreateReplyCommand.java - Copyright © 2011–2016 David Roden + * Sone - CreateReplyCommand.java - Copyright © 2011–2019 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 @@ -30,7 +30,6 @@ import freenet.support.SimpleFieldSet; * FCP command that creates a new {@link Reply}. * * @see Core#createReply(Sone, Post, String) - * @author David ‘Bombe’ Roden */ public class CreateReplyCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/DeletePostCommand.java b/src/main/java/net/pterodactylus/sone/fcp/DeletePostCommand.java index b5ace1d..c93029f 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/DeletePostCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/DeletePostCommand.java @@ -1,5 +1,5 @@ /* - * Sone - DeletePostCommand.java - Copyright © 2011–2016 David Roden + * Sone - DeletePostCommand.java - Copyright © 2011–2019 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 @@ -27,7 +27,6 @@ import freenet.support.SimpleFieldSet; * FCP command that deletes a {@link Post}. * * @see Core#deletePost(Post) - * @author David ‘Bombe’ Roden */ public class DeletePostCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java index d75603e..4531f93 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java @@ -1,5 +1,5 @@ /* - * Sone - DeleteReplyCommand.java - Copyright © 2011–2016 David Roden + * Sone - DeleteReplyCommand.java - Copyright © 2011–2019 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 @@ -27,7 +27,6 @@ import freenet.support.SimpleFieldSet; * FCP command that deletes a {@link PostReply}. * * @see Core#deleteReply(PostReply) - * @author David ‘Bombe’ Roden */ public class DeleteReplyCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java index 6f28518..0b321f4 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java +++ b/src/main/java/net/pterodactylus/sone/fcp/FcpInterface.java @@ -1,5 +1,5 @@ /* - * Sone - FcpInterface.java - Copyright © 2011–2016 David Roden + * Sone - FcpInterface.java - Copyright © 2011–2019 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 @@ -54,16 +54,12 @@ import com.google.inject.Inject; /** * Implementation of an FCP interface for other clients or plugins to * communicate with Sone. - * - * @author David ‘Bombe’ Roden */ @Singleton public class FcpInterface { /** * The action level that full access for the FCP connection is required. - * - * @author David ‘Bombe’ Roden */ public enum FullAccessRequired { @@ -85,7 +81,7 @@ public class FcpInterface { private final AtomicBoolean active = new AtomicBoolean(); /** What function full access is required for. */ - private final AtomicReference fullAccessRequired = new AtomicReference(FullAccessRequired.ALWAYS); + private final AtomicReference fullAccessRequired = new AtomicReference<>(FullAccessRequired.ALWAYS); /** All available FCP commands. */ private final Map commands; diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetLocalSonesCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetLocalSonesCommand.java index a55a81c..1427fe7 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetLocalSonesCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetLocalSonesCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetLocalSonesCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetLocalSonesCommand.java - Copyright © 2011–2019 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 @@ -17,14 +17,14 @@ package net.pterodactylus.sone.fcp; +import static net.pterodactylus.sone.fcp.AbstractSoneCommandKt.encodeSones; + import net.pterodactylus.sone.core.Core; import freenet.support.SimpleFieldSet; /** * Implements the “GetLocalSones” FCP command that returns the list of local * Sones to the sender. - * - * @author David ‘Bombe’ Roden */ public class GetLocalSonesCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetPostCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetPostCommand.java index a6f1ae8..d1dc643 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetPostCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetPostCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetPostCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetPostCommand.java - Copyright © 2011–2019 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 @@ -24,8 +24,6 @@ import freenet.support.SimpleFieldSet; /** * The “GetPost” FCP command returns a single {@link Post} to an FCP client. - * - * @author David ‘Bombe’ Roden */ public class GetPostCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java index 4ee15e3..bf80dc2 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetPostFeedCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetPostFeedCommand.java - Copyright © 2011–2019 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 @@ -35,8 +35,6 @@ import freenet.support.SimpleFieldSet; /** * Implementation of an FCP interface for other clients or plugins to * communicate with Sone. - * - * @author David ‘Bombe’ Roden */ public class GetPostFeedCommand extends AbstractSoneCommand { @@ -59,7 +57,7 @@ public class GetPostFeedCommand extends AbstractSoneCommand { int startPost = getInt(parameters, "StartPost", 0); int maxPosts = getInt(parameters, "MaxPosts", -1); - Collection allPosts = new HashSet(); + Collection allPosts = new HashSet<>(); allPosts.addAll(sone.getPosts()); for (String friendSoneId : sone.getFriends()) { Sone friendSone = getCore().getSone(friendSoneId); @@ -71,7 +69,7 @@ public class GetPostFeedCommand extends AbstractSoneCommand { allPosts.addAll(getCore().getDirectedPosts(sone.getId())); allPosts = Collections2.filter(allPosts, Post.FUTURE_POSTS_FILTER); - List sortedPosts = new ArrayList(allPosts); + List sortedPosts = new ArrayList<>(allPosts); Collections.sort(sortedPosts, Post.NEWEST_FIRST); if (sortedPosts.size() < startPost) { diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetPostsCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetPostsCommand.java index b9932a6..9cc131b 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetPostsCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetPostsCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetPostsCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetPostsCommand.java - Copyright © 2011–2019 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 @@ -29,8 +29,6 @@ import freenet.support.SimpleFieldSet; /** * Implements the “GetPosts” FCP command that returns the list of posts a Sone * made. - * - * @author David ‘Bombe’ Roden */ public class GetPostsCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetSoneCommand.java index 9d0e0b7..a4b936b 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetSoneCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetSoneCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetSoneCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetSoneCommand.java - Copyright © 2011–2019 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 @@ -17,6 +17,8 @@ package net.pterodactylus.sone.fcp; +import static net.pterodactylus.sone.fcp.AbstractSoneCommandKt.encodeSone; + import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Sone; @@ -29,8 +31,6 @@ import freenet.support.SimpleFieldSet; /** * Implements the “GetSone“ FCP command which returns {@link Profile} * information about a {@link Sone}. - * - * @author David ‘Bombe’ Roden */ public class GetSoneCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetSonesCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetSonesCommand.java index fa805e1..ec43143 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetSonesCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetSonesCommand.java @@ -1,5 +1,5 @@ /* - * Sone - GetSonesCommand.java - Copyright © 2011–2016 David Roden + * Sone - GetSonesCommand.java - Copyright © 2011–2019 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 @@ -17,6 +17,8 @@ package net.pterodactylus.sone.fcp; +import static net.pterodactylus.sone.fcp.AbstractSoneCommandKt.encodeSones; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,8 +29,6 @@ import freenet.support.SimpleFieldSet; /** * Implements the “GetSones” FCP command that returns the list of known Sones. - * - * @author David ‘Bombe’ Roden */ public class GetSonesCommand extends AbstractSoneCommand { @@ -49,7 +49,7 @@ public class GetSonesCommand extends AbstractSoneCommand { public Response execute(SimpleFieldSet parameters) { int startSone = getInt(parameters, "StartSone", 0); int maxSones = getInt(parameters, "MaxSones", -1); - List sones = new ArrayList(getCore().getSones()); + List sones = new ArrayList<>(getCore().getSones()); if (sones.size() < startSone) { return new Response("Sones", encodeSones(Collections. emptyList(), "Sones.")); } diff --git a/src/main/java/net/pterodactylus/sone/fcp/LikePostCommand.java b/src/main/java/net/pterodactylus/sone/fcp/LikePostCommand.java index a2fdd18..edd5a43 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/LikePostCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/LikePostCommand.java @@ -1,5 +1,5 @@ /* - * Sone - LikePostCommand.java - Copyright © 2011–2016 David Roden + * Sone - LikePostCommand.java - Copyright © 2011–2019 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 @@ -26,8 +26,6 @@ import freenet.support.SimpleFieldSet; /** * Implements the “LikePost” FCP command which allows the user to like a post. - * - * @author David ‘Bombe’ Roden */ public class LikePostCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java index 6fba11b..800e43c 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java @@ -1,5 +1,5 @@ /* - * Sone - LikeReplyCommand.java - Copyright © 2011–2016 David Roden + * Sone - LikeReplyCommand.java - Copyright © 2011–2019 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 @@ -26,8 +26,6 @@ import freenet.support.SimpleFieldSet; /** * Implements the “LikeReply” FCP command which allows the user to like a reply. - * - * @author David ‘Bombe’ Roden */ public class LikeReplyCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/LockSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/LockSoneCommand.java index f39a18c..691bc4b 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/LockSoneCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/LockSoneCommand.java @@ -1,5 +1,5 @@ /* - * Sone - LockSoneCommand.java - Copyright © 2013–2016 David Roden + * Sone - LockSoneCommand.java - Copyright © 2013–2019 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 @@ -30,8 +30,6 @@ import com.google.common.base.Optional; * Implements the “LockSone” FCP command. If a valid local Sone was given as * parameter “Sone,” this command will always lock the Sone and reply with * “SoneLocked.” - * - * @author David ‘Bombe’ Roden */ public class LockSoneCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/UnlockSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/UnlockSoneCommand.java index bc78441..ca5a59e 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/UnlockSoneCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/UnlockSoneCommand.java @@ -1,5 +1,5 @@ /* - * Sone - UnlockSoneCommand.java - Copyright © 2013–2016 David Roden + * Sone - UnlockSoneCommand.java - Copyright © 2013–2019 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 @@ -30,8 +30,6 @@ import com.google.common.base.Optional; * Implements the “UnlockSone” FCP command. If a valid local Sone was given as * parameter “Sone,” this command will always unlock the Sone and reply with * “SoneUnlocked.” - * - * @author David ‘Bombe’ Roden */ public class UnlockSoneCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/VersionCommand.java b/src/main/java/net/pterodactylus/sone/fcp/VersionCommand.java index 5f50b4d..7acea2d 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/VersionCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/VersionCommand.java @@ -1,5 +1,5 @@ /* - * Sone - VersionCommand.java - Copyright © 2011–2016 David Roden + * Sone - VersionCommand.java - Copyright © 2011–2019 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 @@ -24,8 +24,6 @@ import freenet.support.SimpleFieldSet; /** * Returns version information about the Sone plugin. - * - * @author David ‘Bombe’ Roden */ public class VersionCommand extends AbstractSoneCommand { diff --git a/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceActivatedEvent.java b/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceActivatedEvent.java index 56b658a..f45ac53 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceActivatedEvent.java +++ b/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceActivatedEvent.java @@ -5,8 +5,6 @@ import net.pterodactylus.sone.fcp.FcpInterface; /** * Event that signals that the {@link FcpInterface} was activated in the * configuration. - * - * @author David ‘Bombe’ Roden */ public class FcpInterfaceActivatedEvent { diff --git a/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceDeactivatedEvent.java b/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceDeactivatedEvent.java index b97ef76..216960b 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceDeactivatedEvent.java +++ b/src/main/java/net/pterodactylus/sone/fcp/event/FcpInterfaceDeactivatedEvent.java @@ -5,8 +5,6 @@ import net.pterodactylus.sone.fcp.FcpInterface; /** * Event that signals that the {@link FcpInterface} was deactivated in the * configuration. - * - * @author David ‘Bombe’ Roden */ public class FcpInterfaceDeactivatedEvent { diff --git a/src/main/java/net/pterodactylus/sone/fcp/event/FullAccessRequiredChanged.java b/src/main/java/net/pterodactylus/sone/fcp/event/FullAccessRequiredChanged.java index 9638880..86c20a3 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/event/FullAccessRequiredChanged.java +++ b/src/main/java/net/pterodactylus/sone/fcp/event/FullAccessRequiredChanged.java @@ -6,8 +6,6 @@ import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; /** * Event that signals that the {@link FcpInterface}’s {@link * FullAccessRequired} parameter was changed in the configuration. - * - * @author David ‘Bombe’ Roden */ public class FullAccessRequiredChanged { diff --git a/src/main/java/net/pterodactylus/sone/freenet/Key.java b/src/main/java/net/pterodactylus/sone/freenet/Key.java index f21e2f6..6811642 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/Key.java +++ b/src/main/java/net/pterodactylus/sone/freenet/Key.java @@ -10,8 +10,6 @@ import com.google.common.annotations.VisibleForTesting; /** * Encapsulates the parts of a {@link FreenetURI} that do not change while * being converted from SSK to USK and/or back. - * - * @author David ‘Bombe’ Roden */ public class Key { diff --git a/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java b/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java index 7ca9a5c..d667811 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java +++ b/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java @@ -1,5 +1,5 @@ /* - * Sone - L10nFilter.java - Copyright © 2010–2016 David Roden + * Sone - L10nFilter.java - Copyright © 2010–2019 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 @@ -25,29 +25,21 @@ import java.util.Map; import javax.annotation.Nonnull; -import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.util.template.Filter; import net.pterodactylus.util.template.TemplateContext; +import freenet.l10n.BaseL10n; + /** * {@link Filter} implementation replaces {@link String} values with their * translated equivalents. - * - * @author David ‘Bombe’ Roden */ public class L10nFilter implements Filter { - /** The web interface. */ - private final WebInterface webInterface; + private final BaseL10n l10n; - /** - * Creates a new L10n filter. - * - * @param webInterface - * The Sone web interface - */ - public L10nFilter(WebInterface webInterface) { - this.webInterface = webInterface; + public L10nFilter(BaseL10n l10n) { + this.l10n = l10n; } /** @@ -58,9 +50,9 @@ public class L10nFilter implements Filter { List parameterValues = getParameters(data, parameters); String text = getText(data); if (parameterValues.isEmpty()) { - return webInterface.getL10n().getString(text); + return l10n.getString(text); } - return new MessageFormat(webInterface.getL10n().getString(text), new Locale(webInterface.getL10n().getSelectedLanguage().shortCode)).format(parameterValues.toArray()); + return new MessageFormat(l10n.getString(text), new Locale(l10n.getSelectedLanguage().shortCode)).format(parameterValues.toArray()); } @Nonnull @@ -73,7 +65,7 @@ public class L10nFilter implements Filter { if (data instanceof L10nText) { return ((L10nText) data).getParameters(); } - List parameterValues = new ArrayList(); + List parameterValues = new ArrayList<>(); int parameterIndex = 0; while (parameters.containsKey(String.valueOf(parameterIndex))) { Object value = parameters.get(String.valueOf(parameterIndex)); diff --git a/src/main/java/net/pterodactylus/sone/freenet/PluginStoreConfigurationBackend.java b/src/main/java/net/pterodactylus/sone/freenet/PluginStoreConfigurationBackend.java index 55e4024..cce544f 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/PluginStoreConfigurationBackend.java +++ b/src/main/java/net/pterodactylus/sone/freenet/PluginStoreConfigurationBackend.java @@ -1,5 +1,5 @@ /* - * Sone - PluginStoreConfigurationBackend.java - Copyright © 2010–2016 David Roden + * Sone - PluginStoreConfigurationBackend.java - Copyright © 2010–2019 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 @@ -31,8 +31,6 @@ import freenet.pluginmanager.PluginStore; /** * Backend for a {@link Configuration} that is based on a {@link PluginStore}. - * - * @author David ‘Bombe’ Roden */ public class PluginStoreConfigurationBackend implements ExtendedConfigurationBackend { diff --git a/src/main/java/net/pterodactylus/sone/freenet/SimpleFieldSetBuilder.java b/src/main/java/net/pterodactylus/sone/freenet/SimpleFieldSetBuilder.java index 25088fc..48eb4bf 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/SimpleFieldSetBuilder.java +++ b/src/main/java/net/pterodactylus/sone/freenet/SimpleFieldSetBuilder.java @@ -1,5 +1,5 @@ /* - * Sone - SimpleFieldSetBuilder.java - Copyright © 2011–2016 David Roden + * Sone - SimpleFieldSetBuilder.java - Copyright © 2011–2019 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 @@ -23,8 +23,6 @@ import freenet.support.SimpleFieldSet; /** * Helper class to construct {@link SimpleFieldSet} objects in a single call. - * - * @author David ‘Bombe’ Roden */ public class SimpleFieldSetBuilder { diff --git a/src/main/java/net/pterodactylus/sone/freenet/fcp/AbstractCommand.java b/src/main/java/net/pterodactylus/sone/freenet/fcp/AbstractCommand.java index b39d905..3ea4804 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/fcp/AbstractCommand.java +++ b/src/main/java/net/pterodactylus/sone/freenet/fcp/AbstractCommand.java @@ -1,5 +1,5 @@ /* - * Sone - AbstractCommand.java - Copyright © 2011–2016 David Roden + * Sone - AbstractCommand.java - Copyright © 2011–2019 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 @@ -23,8 +23,6 @@ import freenet.support.SimpleFieldSet; /** * Basic implementation of a {@link Command} with various helper methods to * simplify processing of input parameters. - * - * @author David ‘Bombe’ Roden */ public abstract class AbstractCommand implements Command { diff --git a/src/main/java/net/pterodactylus/sone/freenet/fcp/Command.java b/src/main/java/net/pterodactylus/sone/freenet/fcp/Command.java index 17f8370..63fc8eb 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/fcp/Command.java +++ b/src/main/java/net/pterodactylus/sone/freenet/fcp/Command.java @@ -1,5 +1,5 @@ /* - * Sone - Command.java - Copyright © 2011–2016 David Roden + * Sone - Command.java - Copyright © 2011–2019 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 @@ -23,8 +23,6 @@ import freenet.support.SimpleFieldSet; /** * Implementation of an FCP interface for other clients or plugins to * communicate with Sone. - * - * @author David ‘Bombe’ Roden */ public interface Command { @@ -42,8 +40,6 @@ public interface Command { /** * The access type of the request. - * - * @author David ‘Bombe’ Roden */ public static enum AccessType { @@ -60,8 +56,6 @@ public interface Command { /** * Interface for command replies. - * - * @author David ‘Bombe’ Roden */ public static class Response { @@ -98,8 +92,6 @@ public interface Command { /** * Response implementation that can return an error message and an optional * error code. - * - * @author David ‘Bombe’ Roden */ public class ErrorResponse extends Response { diff --git a/src/main/java/net/pterodactylus/sone/freenet/fcp/FcpException.java b/src/main/java/net/pterodactylus/sone/freenet/fcp/FcpException.java index c28eef7..0e156a1 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/fcp/FcpException.java +++ b/src/main/java/net/pterodactylus/sone/freenet/fcp/FcpException.java @@ -1,5 +1,5 @@ /* - * Sone - FcpException.java - Copyright © 2011–2016 David Roden + * Sone - FcpException.java - Copyright © 2011–2019 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 @@ -19,8 +19,6 @@ package net.pterodactylus.sone.freenet.fcp; /** * Base exception for FCP communication. - * - * @author David ‘Bombe’ Roden */ public class FcpException extends Exception { diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java index 0090aa8..fbaabb3 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java @@ -1,5 +1,5 @@ /* - * Sone - PluginConnector.java - Copyright © 2010–2016 David Roden + * Sone - PluginConnector.java - Copyright © 2010–2019 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 @@ -33,8 +33,6 @@ import freenet.support.api.Bucket; /** * Interface for talking to other plugins. Other plugins are identified by their * name and a unique connection identifier. - * - * @author David ‘Bombe’ Roden */ @Singleton public class PluginConnector implements FredPluginTalker { diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java index 09b186e..e263a60 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java @@ -1,5 +1,5 @@ /* - * Sone - PluginException.java - Copyright © 2010–2016 David Roden + * Sone - PluginException.java - Copyright © 2010–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.freenet.wot.WebOfTrustException; /** * Exception that signals an error when communicating with a plugin. - * - * @author David ‘Bombe’ Roden */ public class PluginException extends WebOfTrustException { diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java index 56a1d46..ce2ba7f 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/event/ReceivedReplyEvent.java @@ -1,5 +1,5 @@ /* - * Sone - ReceivedReplyEvent.java - Copyright © 2013–2016 David Roden + * Sone - ReceivedReplyEvent.java - Copyright © 2013–2019 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 @@ -23,8 +23,6 @@ import freenet.support.api.Bucket; /** * Event that signals that a plugin reply was received. - * - * @author David ‘Bombe’ Roden */ public class ReceivedReplyEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Context.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Context.java index 13f9793..b386bdb 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/Context.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Context.java @@ -1,5 +1,5 @@ /* - * Sone - Context.java - Copyright © 2014–2016 David Roden + * Sone - Context.java - Copyright © 2014–2019 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 @@ -24,8 +24,6 @@ import com.google.common.base.Function; /** * Custom container for the Web of Trust context. This allows easier * configuration of dependency injection. - * - * @author David ‘Bombe’ Roden */ public class Context { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java index 433516f..0d92d61 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java @@ -1,5 +1,5 @@ /* - * Sone - DefaultIdentity.java - Copyright © 2010–2016 David Roden + * Sone - DefaultIdentity.java - Copyright © 2010–2019 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 @@ -26,8 +26,6 @@ import java.util.Set; /** * A Web of Trust identity. - * - * @author David ‘Bombe’ Roden */ public class DefaultIdentity implements Identity { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java index 2f78943..e2e3a74 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java @@ -1,5 +1,5 @@ /* - * Sone - DefaultOwnIdentity.java - Copyright © 2010–2016 David Roden + * Sone - DefaultOwnIdentity.java - Copyright © 2010–2019 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 @@ -22,8 +22,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * An own identity is an identity that the owner of the node has full control * over. - * - * @author David ‘Bombe’ Roden */ public class DefaultOwnIdentity extends DefaultIdentity implements OwnIdentity { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java index 25ddf9c..a99aac0 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java @@ -1,5 +1,5 @@ /* - * Sone - Identity.java - Copyright © 2010–2016 David Roden + * Sone - Identity.java - Copyright © 2010–2019 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 @@ -28,8 +28,6 @@ import com.google.common.base.Function; * Interface for web of trust identities, defining all functions that can be * performed on an identity. An identity is only a container for identity data * and will not perform any updating in the WebOfTrust plugin itself. - * - * @author David ‘Bombe’ Roden */ public interface Identity { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.java index f014de5..8b28011 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetector.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityChangeDetector.java - Copyright © 2013–2016 David Roden + * Sone - IdentityChangeDetector.java - Copyright © 2013–2019 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 @@ -38,8 +38,6 @@ import com.google.common.collect.ImmutableMap; * 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. - * - * @author David ‘Bombe’ Roden */ public class IdentityChangeDetector { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSender.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSender.java index b3c3c05..fd57c38 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSender.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSender.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityChangeEventSender.java - Copyright © 2013–2016 David Roden + * Sone - IdentityChangeEventSender.java - Copyright © 2013–2019 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 @@ -33,7 +33,6 @@ import com.google.common.eventbus.EventBus; * Detects changes in {@link Identity}s trusted my multiple {@link * OwnIdentity}s. * - * @author David ‘Bombe’ Roden * @see IdentityChangeDetector */ public class IdentityChangeEventSender { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityLoader.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityLoader.java index 1a8cc49..f16df1c 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityLoader.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityLoader.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityLoader.java - Copyright © 2013–2016 David Roden + * Sone - IdentityLoader.java - Copyright © 2013–2019 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 @@ -33,8 +33,6 @@ import com.google.inject.Inject; /** * Loads {@link OwnIdentity}s and the {@link Identity}s they trust. - * - * @author David ‘Bombe’ Roden */ public class IdentityLoader { @@ -57,7 +55,7 @@ public class IdentityLoader { } private Map> loadTrustedIdentitiesForOwnIdentities(Collection ownIdentities) throws PluginException { - Map> currentIdentities = new HashMap>(); + Map> currentIdentities = new HashMap<>(); for (OwnIdentity ownIdentity : ownIdentities) { if (identityDoesNotHaveTheCorrectContext(ownIdentity)) { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java index d3ba606..c0f6f1b 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManager.java @@ -10,8 +10,6 @@ import com.google.inject.ImplementedBy; /** * Connects to a {@link WebOfTrustConnector} and sends identity events to an * {@link EventBus}. - * - * @author David ‘Bombe’ Roden */ @ImplementedBy(IdentityManagerImpl.class) public interface IdentityManager extends Service { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManagerImpl.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManagerImpl.java index 02e91ce..6f46465 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManagerImpl.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityManagerImpl.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityManagerImpl.java - Copyright © 2010–2016 David Roden + * Sone - IdentityManagerImpl.java - Copyright © 2010–2019 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 @@ -43,8 +43,6 @@ import com.google.inject.Singleton; * It is also responsible for polling identities from the Web of Trust plugin * and sending events to the {@link EventBus} when {@link Identity}s and * {@link OwnIdentity}s are discovered or disappearing. - * - * @author David ‘Bombe’ Roden */ @Singleton public class IdentityManagerImpl extends AbstractService implements IdentityManager { @@ -109,7 +107,7 @@ public class IdentityManagerImpl extends AbstractService implements IdentityMana @Override public Set getAllOwnIdentities() { synchronized (currentOwnIdentities) { - return new HashSet(currentOwnIdentities); + return new HashSet<>(currentOwnIdentities); } } @@ -122,7 +120,7 @@ public class IdentityManagerImpl extends AbstractService implements IdentityMana */ @Override protected void serviceRun() { - Map> oldIdentities = new HashMap>(); + Map> oldIdentities = new HashMap<>(); while (!shouldStop()) { try { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java index 8be0571..500f2c7 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java @@ -1,5 +1,5 @@ /* - * Sone - OwnIdentity.java - Copyright © 2010–2016 David Roden + * Sone - OwnIdentity.java - Copyright © 2010–2019 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 @@ -20,8 +20,6 @@ package net.pterodactylus.sone.freenet.wot; /** * Defines a local identity, an own identity. - * - * @author David ‘Bombe’ Roden */ public interface OwnIdentity extends Identity { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java index 7b18888..2da00f6 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java @@ -1,5 +1,5 @@ /* - * Sone - Trust.java - Copyright © 2010–2016 David Roden + * Sone - Trust.java - Copyright © 2010–2019 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 @@ -23,8 +23,6 @@ import com.google.common.base.Objects; /** * Container class for trust in the web of trust. - * - * @author David ‘Bombe’ Roden */ public class Trust { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index 5f7b8b7..c1dbef9 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -1,5 +1,5 @@ /* - * Sone - WebOfTrustConnector.java - Copyright © 2010–2016 David Roden + * Sone - WebOfTrustConnector.java - Copyright © 2010–2019 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 @@ -43,8 +43,6 @@ import freenet.support.api.Bucket; /** * Connector for the Web of Trust plugin. - * - * @author David ‘Bombe’ Roden */ @Singleton public class WebOfTrustConnector { @@ -98,7 +96,7 @@ public class WebOfTrustConnector { Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetOwnIdentities").get()); SimpleFieldSet fields = reply.getFields(); int ownIdentityCounter = -1; - Set ownIdentities = new HashSet(); + Set ownIdentities = new HashSet<>(); while (true) { String id = fields.get("Identity" + ++ownIdentityCounter); if (id == null) { @@ -144,7 +142,7 @@ public class WebOfTrustConnector { public Set loadTrustedIdentities(OwnIdentity ownIdentity, Optional context) throws PluginException { Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", context.or("")).put("WantTrustValues", "true").get()); SimpleFieldSet fields = reply.getFields(); - Set identities = new HashSet(); + Set identities = new HashSet<>(); int identityCounter = -1; while (true) { String id = fields.get("Identity" + ++identityCounter); @@ -331,7 +329,7 @@ public class WebOfTrustConnector { * @return The parsed contexts */ private static Set parseContexts(String prefix, SimpleFieldSet fields) { - Set contexts = new HashSet(); + Set contexts = new HashSet<>(); int contextCounter = -1; while (true) { String context = fields.get(prefix + "Context" + ++contextCounter); @@ -353,7 +351,7 @@ public class WebOfTrustConnector { * @return The parsed properties */ private static Map parseProperties(String prefix, SimpleFieldSet fields) { - Map properties = new HashMap(); + Map properties = new HashMap<>(); int propertiesCounter = -1; while (true) { String propertyName = fields.get(prefix + "Property" + ++propertiesCounter + ".Name"); @@ -443,8 +441,6 @@ public class WebOfTrustConnector { /** * Container for the data of the reply from a plugin. - * - * @author David ‘Bombe’ Roden */ private static class Reply { @@ -502,8 +498,6 @@ public class WebOfTrustConnector { /** * Helper method to create {@link SimpleFieldSet}s with terser code. - * - * @author David ‘Bombe’ Roden */ private static class SimpleFieldSetConstructor { @@ -578,8 +572,6 @@ public class WebOfTrustConnector { /** * Container for identifying plugins. Plugins are identified by their plugin * name and their unique identifier. - * - * @author David Roden */ private static class PluginIdentifier { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java index c622b3c..954fe04 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java @@ -1,5 +1,5 @@ /* - * Sone - WebOfTrustException.java - Copyright © 2010–2016 David Roden + * Sone - WebOfTrustException.java - Copyright © 2010–2019 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 @@ -20,8 +20,6 @@ package net.pterodactylus.sone.freenet.wot; /** * Exception that signals an error processing web of trust identities, mostly * when communicating with the web of trust plugin. - * - * @author David ‘Bombe’ Roden */ public class WebOfTrustException extends Exception { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityAddedEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityAddedEvent.java index 323a9cf..2d7ab32 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityAddedEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityAddedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityAddedEvent.java - Copyright © 2013–2016 David Roden + * Sone - IdentityAddedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Event that signals that an {@link Identity} was added. - * - * @author David ‘Bombe’ Roden */ public class IdentityAddedEvent extends IdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityEvent.java index 6289c8a..8a23ae1 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityEvent.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityEvent.java - Copyright © 2013–2016 David Roden + * Sone - IdentityEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Base class for {@link Identity} events. - * - * @author David ‘Bombe’ Roden */ public abstract class IdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityRemovedEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityRemovedEvent.java index a586de0..655015e 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityRemovedEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityRemovedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityRemovedEvent.java - Copyright © 2013–2016 David Roden + * Sone - IdentityRemovedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Event that signals that an {@link Identity} was removed. - * - * @author David ‘Bombe’ Roden */ public class IdentityRemovedEvent extends IdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityUpdatedEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityUpdatedEvent.java index 3e9a0f7..a71ad5b 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityUpdatedEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/IdentityUpdatedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityUpdatedEvent.java - Copyright © 2013–2016 David Roden + * Sone - IdentityUpdatedEvent.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Event that signals that an {@link Identity} was updated. - * - * @author David ‘Bombe’ Roden */ public class IdentityUpdatedEvent extends IdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityAddedEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityAddedEvent.java index cdb787a..fc34848 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityAddedEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityAddedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - OwnIdentityAddedEvent.java - Copyright © 2013–2016 David Roden + * Sone - OwnIdentityAddedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Event that signals that an {@link OwnIdentity} was added. - * - * @author David ‘Bombe’ Roden */ public class OwnIdentityAddedEvent extends OwnIdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEvent.java index 91ad281..9e88d20 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEvent.java @@ -1,5 +1,5 @@ /* - * Sone - OwnIdentityEvent.java - Copyright © 2013–2016 David Roden + * Sone - OwnIdentityEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Base class for {@link OwnIdentity} events. - * - * @author David ‘Bombe’ Roden */ public abstract class OwnIdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityRemovedEvent.java b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityRemovedEvent.java index 5b6bd95..73761b0 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityRemovedEvent.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityRemovedEvent.java @@ -1,5 +1,5 @@ /* - * Sone - OwnIdentityRemovedEvent.java - Copyright © 2013–2016 David Roden + * Sone - OwnIdentityRemovedEvent.java - Copyright © 2013–2019 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 @@ -21,8 +21,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; /** * Event that signals that an {@link OwnIdentity} was removed. - * - * @author David ‘Bombe’ Roden */ public class OwnIdentityRemovedEvent extends OwnIdentityEvent { diff --git a/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java b/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java index d0168ae..c42b056 100644 --- a/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java +++ b/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java @@ -12,8 +12,6 @@ import net.pterodactylus.util.web.Request; /** * {@link Loaders} implementation that loads all resources from the filesystem. - * - * @author David ‘Bombe’ Roden */ public class DebugLoaders implements Loaders { @@ -30,7 +28,7 @@ public class DebugLoaders implements Loaders { @Override public Page loadStaticPage(String basePath, String prefix, String mimeType) { - return new ReloadingPage(basePath, new File(filesystemPath, prefix).getAbsolutePath(), mimeType); + return new ReloadingPage<>(basePath, new File(filesystemPath, prefix).getAbsolutePath(), mimeType); } @Override diff --git a/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java b/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java index e94e655..72d8d19 100644 --- a/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java +++ b/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java @@ -18,8 +18,6 @@ import net.pterodactylus.util.web.StaticPage; /** * Default {@link Loaders} implementation that loads resources from the classpath. - * - * @author David ‘Bombe’ Roden */ public class DefaultLoaders implements Loaders { diff --git a/src/main/java/net/pterodactylus/sone/main/Loaders.java b/src/main/java/net/pterodactylus/sone/main/Loaders.java index 34ee1b1..8ee5132 100644 --- a/src/main/java/net/pterodactylus/sone/main/Loaders.java +++ b/src/main/java/net/pterodactylus/sone/main/Loaders.java @@ -9,8 +9,6 @@ import com.google.inject.ImplementedBy; /** * Defines loaders for resources that can be loaded from various locations. - * - * @author David ‘Bombe’ Roden */ @ImplementedBy(DefaultLoaders.class) public interface Loaders { diff --git a/src/main/java/net/pterodactylus/sone/main/ReparseFilter.java b/src/main/java/net/pterodactylus/sone/main/ReparseFilter.java index acad00b..4f7c5cb 100644 --- a/src/main/java/net/pterodactylus/sone/main/ReparseFilter.java +++ b/src/main/java/net/pterodactylus/sone/main/ReparseFilter.java @@ -12,8 +12,6 @@ import net.pterodactylus.util.template.TemplateParser; /** * Takes the input and parses it as a new {@link Template}. - * - * @author David ‘Bombe’ Roden */ public class ReparseFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index 5cf708f..649ebf6 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -1,5 +1,5 @@ /* - * Sone - SonePlugin.java - Copyright © 2010–2016 David Roden + * Sone - SonePlugin.java - Copyright © 2010–2019 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 @@ -30,12 +30,15 @@ import javax.inject.Singleton; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.database.Database; +import net.pterodactylus.sone.database.PostProvider; +import net.pterodactylus.sone.database.SoneProvider; import net.pterodactylus.sone.database.memory.MemoryDatabase; import net.pterodactylus.sone.fcp.FcpInterface; import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend; import net.pterodactylus.sone.freenet.wot.Context; import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector; import net.pterodactylus.sone.web.WebInterface; +import net.pterodactylus.sone.web.WebInterfaceModule; import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.config.MapConfigurationBackend; @@ -49,6 +52,7 @@ import com.google.common.eventbus.EventBus; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.Module; import com.google.inject.TypeLiteral; import com.google.inject.matcher.Matchers; import com.google.inject.spi.InjectionListener; @@ -56,6 +60,7 @@ import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; import freenet.client.async.PersistenceDisabledException; +import freenet.l10n.BaseL10n; import freenet.l10n.BaseL10n.LANGUAGE; import freenet.l10n.PluginL10n; import freenet.pluginmanager.FredPlugin; @@ -72,8 +77,6 @@ import freenet.support.api.Bucket; /** * This class interfaces with Freenet. It is the class that is loaded by the * node and starts up the whole Sone system. - * - * @author David ‘Bombe’ Roden */ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, FredPluginBaseL10n, FredPluginThreadless, FredPluginVersioned { @@ -119,9 +122,9 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr } /** The current year at time of release. */ - private static final int YEAR = 2017; + private static final int YEAR = 2019; private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/"; - private static final int LATEST_EDITION = 77; + private static final int LATEST_EDITION = 78; /** The logger. */ private static final Logger logger = getLogger(SonePlugin.class.getName()); @@ -180,11 +183,11 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr return (version == null) ? "unknown" : version.getNice(); } - public static int getYear() { + public int getYear() { return YEAR; } - public static String getHomepage() { + public String getHomepage() { return SONE_HOMEPAGE + LATEST_EDITION; } @@ -257,6 +260,9 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr bind(PluginYear.class).toInstance(new PluginYear(getYear())); bind(PluginHomepage.class).toInstance(new PluginHomepage(getHomepage())); bind(Database.class).to(MemoryDatabase.class).in(Singleton.class); + bind(BaseL10n.class).toInstance(l10n.getBase()); + bind(SoneProvider.class).to(Core.class).in(Singleton.class); + bind(PostProvider.class).to(Core.class).in(Singleton.class); if (startConfiguration.getBooleanValue("Developer.LoadFromFilesystem").getValue(false)) { String path = startConfiguration.getStringValue("Developer.FilesystemPath").getValue(null); if (path != null) { @@ -284,7 +290,8 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr } }; - Injector injector = Guice.createInjector(freenetModule, soneModule); + Module webInterfaceModule = new WebInterfaceModule(); + Injector injector = Guice.createInjector(freenetModule, soneModule, webInterfaceModule); core = injector.getInstance(Core.class); /* create web of trust connector. */ @@ -410,46 +417,4 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr return getPluginVersion(); } - public static class PluginVersion { - - private final String version; - - public PluginVersion(String version) { - this.version = version; - } - - public String getVersion() { - return version; - } - - } - - public static class PluginYear { - - private final int year; - - public PluginYear(int year) { - this.year = year; - } - - public int getYear() { - return year; - } - - } - - public static class PluginHomepage { - - private final String homepage; - - public PluginHomepage(String homepage) { - this.homepage = homepage; - } - - public String getHomepage() { - return homepage; - } - - } - } diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.kt b/src/main/java/net/pterodactylus/sone/main/SonePlugin.kt new file mode 100644 index 0000000..5e0b2c1 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.kt @@ -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/java/net/pterodactylus/sone/notify/ListNotification.java b/src/main/java/net/pterodactylus/sone/notify/ListNotification.java index 8ab8e4c..6a7b086 100644 --- a/src/main/java/net/pterodactylus/sone/notify/ListNotification.java +++ b/src/main/java/net/pterodactylus/sone/notify/ListNotification.java @@ -1,5 +1,5 @@ /* - * Sone - ListNotification.java - Copyright © 2010–2016 David Roden + * Sone - ListNotification.java - Copyright © 2010–2019 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 @@ -30,7 +30,6 @@ import net.pterodactylus.util.template.Template; * * @param * The type of the items - * @author David ‘Bombe’ Roden */ public class ListNotification extends TemplateNotification { @@ -38,7 +37,7 @@ public class ListNotification extends TemplateNotification { private final String key; /** The list of new elements. */ - private final List elements = new CopyOnWriteArrayList(); + private final List elements = new CopyOnWriteArrayList<>(); /** * Creates a new list notification. @@ -97,7 +96,7 @@ public class ListNotification extends TemplateNotification { * @return The current list of elements */ public List getElements() { - return new ArrayList(elements); + return new ArrayList<>(elements); } /** diff --git a/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilter.java b/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilter.java index 4672e72..50a1087 100644 --- a/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilter.java +++ b/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilter.java @@ -1,5 +1,5 @@ /* - * Sone - ListNotificationFilter.java - Copyright © 2010–2016 David Roden + * Sone - ListNotificationFilter.java - Copyright © 2010–2019 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 @@ -36,8 +36,6 @@ import com.google.common.base.Optional; /** * Filter for {@link ListNotification}s. - * - * @author David ‘Bombe’ Roden */ @Singleton public class ListNotificationFilter { @@ -67,7 +65,7 @@ public class ListNotificationFilter { */ @SuppressWarnings("unchecked") public List filterNotifications(Collection notifications, Sone currentSone) { - List filteredNotifications = new ArrayList(); + List filteredNotifications = new ArrayList<>(); for (Notification notification : notifications) { if (notification.getId().equals("new-sone-notification")) { if ((currentSone != null) && !currentSone.getOptions().isShowNewSoneNotifications()) { @@ -128,7 +126,7 @@ public class ListNotificationFilter { if (newPosts.size() == postNotification.getElements().size()) { return Optional.of(postNotification); } - ListNotification filteredNotification = new ListNotification(postNotification); + ListNotification filteredNotification = new ListNotification<>(postNotification); filteredNotification.setElements(newPosts); filteredNotification.setLastUpdateTime(postNotification.getLastUpdatedTime()); return Optional.of(filteredNotification); @@ -157,7 +155,7 @@ public class ListNotificationFilter { if (newReplies.size() == newReplyNotification.getElements().size()) { return Optional.of(newReplyNotification); } - ListNotification filteredNotification = new ListNotification(newReplyNotification); + ListNotification filteredNotification = new ListNotification<>(newReplyNotification); filteredNotification.setElements(newReplies); filteredNotification.setLastUpdateTime(newReplyNotification.getLastUpdatedTime()); return Optional.of(filteredNotification); diff --git a/src/main/java/net/pterodactylus/sone/notify/PostVisibilityFilter.java b/src/main/java/net/pterodactylus/sone/notify/PostVisibilityFilter.java index 3582e3d..d29d537 100644 --- a/src/main/java/net/pterodactylus/sone/notify/PostVisibilityFilter.java +++ b/src/main/java/net/pterodactylus/sone/notify/PostVisibilityFilter.java @@ -16,8 +16,6 @@ import com.google.common.base.Predicate; /** * Filters {@link Notification}s involving {@link Post}s. - * - * @author David ‘Bombe’ Roden */ @Singleton public class PostVisibilityFilter { diff --git a/src/main/java/net/pterodactylus/sone/notify/ReplyVisibilityFilter.java b/src/main/java/net/pterodactylus/sone/notify/ReplyVisibilityFilter.java index fd13779..5e3e16d 100644 --- a/src/main/java/net/pterodactylus/sone/notify/ReplyVisibilityFilter.java +++ b/src/main/java/net/pterodactylus/sone/notify/ReplyVisibilityFilter.java @@ -16,8 +16,6 @@ import com.google.common.base.Predicate; /** * Filter that checks a {@link PostReply} for visibility. - * - * @author David ‘Bombe’ Roden */ @Singleton public class ReplyVisibilityFilter { diff --git a/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java index 7d0ab90..19b600e 100644 --- a/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - AlbumAccessor.java - Copyright © 2011–2016 David Roden + * Sone - AlbumAccessor.java - Copyright © 2011–2019 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 @@ -31,8 +31,6 @@ import net.pterodactylus.util.template.TemplateContext; * {@link Accessor} implementation for {@link Album}s. A property named * “backlinks” is added, it returns links to all parents and the owner Sone of * an album. - * - * @author David ‘Bombe’ Roden */ public class AlbumAccessor extends ReflectionAccessor { @@ -45,7 +43,7 @@ public class AlbumAccessor extends ReflectionAccessor { public Object get(TemplateContext templateContext, Object object, String member) { Album album = (Album) object; if ("backlinks".equals(member)) { - List backlinks = new ArrayList(); + List backlinks = new ArrayList<>(); Album currentAlbum = album; while (!currentAlbum.isRoot()) { backlinks.add(0, new Link("imageBrowser.html?album=" + currentAlbum.getId(), currentAlbum.getTitle())); @@ -62,8 +60,6 @@ public class AlbumAccessor extends ReflectionAccessor { /** * Container for links. - * - * @author David ‘Bombe’ Roden */ private static class Link { diff --git a/src/main/java/net/pterodactylus/sone/template/CollectionAccessor.java b/src/main/java/net/pterodactylus/sone/template/CollectionAccessor.java index 0771abd..8ce97ad 100644 --- a/src/main/java/net/pterodactylus/sone/template/CollectionAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/CollectionAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - CollectionAccessor.java - Copyright © 2010–2016 David Roden + * Sone - CollectionAccessor.java - Copyright © 2010–2019 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 @@ -35,8 +35,6 @@ import net.pterodactylus.util.template.TemplateContext; *
Returns the nice names of all {@link Sone}s in the collection, sorted * ascending by their nice names.
* - * - * @author David ‘Bombe’ Roden */ public class CollectionAccessor extends ReflectionAccessor { @@ -47,7 +45,7 @@ public class CollectionAccessor extends ReflectionAccessor { public Object get(TemplateContext templateContext, Object object, String member) { Collection collection = (Collection) object; if (member.equals("soneNames")) { - List sones = new ArrayList(); + List sones = new ArrayList<>(); for (Object sone : collection) { if (!(sone instanceof Sone)) { continue; diff --git a/src/main/java/net/pterodactylus/sone/template/CssClassNameFilter.java b/src/main/java/net/pterodactylus/sone/template/CssClassNameFilter.java index 5776b07..1ff4f04 100644 --- a/src/main/java/net/pterodactylus/sone/template/CssClassNameFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/CssClassNameFilter.java @@ -1,5 +1,5 @@ /* - * Sone - CssClassNameFilter.java - Copyright © 2010–2016 David Roden + * Sone - CssClassNameFilter.java - Copyright © 2010–2019 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 @@ -26,8 +26,6 @@ import net.pterodactylus.util.template.TemplateContext; * Converts the {@link String} {@link String#valueOf(Object) representation} of * an object to a valid CSS class name by converting all characters that are not * US-ASCII letters or numbers to an underscore. - * - * @author David ‘Bombe’ Roden */ public class CssClassNameFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/template/FilesystemTemplate.java b/src/main/java/net/pterodactylus/sone/template/FilesystemTemplate.java index ad753a7..7c7da4c 100644 --- a/src/main/java/net/pterodactylus/sone/template/FilesystemTemplate.java +++ b/src/main/java/net/pterodactylus/sone/template/FilesystemTemplate.java @@ -22,15 +22,13 @@ import com.google.common.base.Charsets; /** * {@link Template} implementation that can be reloaded from the filesystem. - * - * @author David ‘Bombe’ Roden */ public class FilesystemTemplate extends Template { private final String filename; - private final AtomicReference lastTemplate = new AtomicReference(); + private final AtomicReference lastTemplate = new AtomicReference<>(); private final TemplateContext initialContext = new TemplateContext(); - private final List parts = new ArrayList(); + private final List parts = new ArrayList<>(); public FilesystemTemplate(String filename) { this.filename = filename; @@ -120,8 +118,6 @@ public class FilesystemTemplate extends Template { /** * Exception that signals that a template file could not be found. - * - * @author David ‘Bombe’ Roden */ public static class TemplateFileNotFoundException extends RuntimeException { diff --git a/src/main/java/net/pterodactylus/sone/template/GetPagePlugin.java b/src/main/java/net/pterodactylus/sone/template/GetPagePlugin.java index 4c8f3d5..172b4b2 100644 --- a/src/main/java/net/pterodactylus/sone/template/GetPagePlugin.java +++ b/src/main/java/net/pterodactylus/sone/template/GetPagePlugin.java @@ -1,5 +1,5 @@ /* - * Sone - GetPagePlugin.java - Copyright © 2010–2016 David Roden + * Sone - GetPagePlugin.java - Copyright © 2010–2019 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 @@ -27,8 +27,6 @@ import net.pterodactylus.util.web.Request; /** * Extracts a page number from a {@link Request}’s parameters and stores it in * the {@link TemplateContext}. - * - * @author David ‘Bombe’ Roden */ public class GetPagePlugin implements Plugin { diff --git a/src/main/java/net/pterodactylus/sone/template/HttpRequestAccessor.java b/src/main/java/net/pterodactylus/sone/template/HttpRequestAccessor.java index 3e7a261..0e6fda0 100644 --- a/src/main/java/net/pterodactylus/sone/template/HttpRequestAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/HttpRequestAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - HttpRequestAccessor.java - Copyright © 2011–2016 David Roden + * Sone - HttpRequestAccessor.java - Copyright © 2011–2019 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 @@ -27,7 +27,6 @@ import freenet.support.api.HTTPRequest; * {@link HTTPRequest}s. * * @see HTTPRequest#getHeader(String) - * @author David ‘Bombe’ Roden */ public class HttpRequestAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/IdentityAccessor.java b/src/main/java/net/pterodactylus/sone/template/IdentityAccessor.java index 7766af3..ed139de 100644 --- a/src/main/java/net/pterodactylus/sone/template/IdentityAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/IdentityAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityAccessor.java - Copyright © 2010–2016 David Roden + * Sone - IdentityAccessor.java - Copyright © 2010–2019 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 @@ -32,8 +32,6 @@ import net.pterodactylus.util.template.TemplateContext; /** * {@link Accessor} implementation that adds a “uniqueNickname” member to an * {@link Identity}. - * - * @author David ‘Bombe’ Roden */ @Singleton public class IdentityAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/ImageAccessor.java b/src/main/java/net/pterodactylus/sone/template/ImageAccessor.java index 903e26c..78c3aeb 100644 --- a/src/main/java/net/pterodactylus/sone/template/ImageAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/ImageAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - ImageAccessor.java - Copyright © 2011–2016 David Roden + * Sone - ImageAccessor.java - Copyright © 2011–2019 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 @@ -32,8 +32,6 @@ import net.pterodactylus.util.template.TemplateContext; *
  • {@code next}: returns the next image in the image’s album, or {@code * null} if the image is the last image of its album.
  • * - * - * @author David ‘Bombe’ Roden */ public class ImageAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java b/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java index 511baf8..fc4b803 100644 --- a/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java @@ -1,5 +1,5 @@ /* - * Sone - ImageLinkFilter.java - Copyright © 2011–2016 David Roden + * Sone - ImageLinkFilter.java - Copyright © 2011–2019 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 @@ -28,6 +28,7 @@ import java.util.Map; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Image; import net.pterodactylus.util.template.Filter; +import net.pterodactylus.util.template.HtmlFilter; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; import net.pterodactylus.util.template.TemplateContextFactory; @@ -39,8 +40,6 @@ import com.google.common.base.Optional; /** * Template filter that turns an {@link Image} into an HTML <img> tag, * using some parameters to influence parameters of the image. - * - * @author David ‘Bombe’ Roden */ public class ImageLinkFilter implements Filter { @@ -51,19 +50,12 @@ public class ImageLinkFilter implements Filter { private final Core core; /** The template context factory. */ - private final TemplateContextFactory templateContextFactory; + private final TemplateContextFactory templateContextFactory = new TemplateContextFactory(); - /** - * Creates a new image link filter. - * - * @param core - * The core - * @param templateContextFactory - * The template context factory - */ - public ImageLinkFilter(Core core, TemplateContextFactory templateContextFactory) { + public ImageLinkFilter(Core core) { this.core = core; - this.templateContextFactory = templateContextFactory; + templateContextFactory.addFilter("html", new HtmlFilter()); + templateContextFactory.addFilter("css", new CssClassNameFilter()); } /** diff --git a/src/main/java/net/pterodactylus/sone/template/JavascriptFilter.java b/src/main/java/net/pterodactylus/sone/template/JavascriptFilter.java index 595f40e..8dd2b04 100644 --- a/src/main/java/net/pterodactylus/sone/template/JavascriptFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/JavascriptFilter.java @@ -1,5 +1,5 @@ /* - * Sone - JavascriptFilter.java - Copyright © 2011–2016 David Roden + * Sone - JavascriptFilter.java - Copyright © 2011–2019 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 @@ -28,8 +28,6 @@ import com.google.common.io.BaseEncoding; * Escapes double quotes, backslashes, carriage returns and line feeds, and * additionally encloses a given string with double quotes to make it possible * to use a string in Javascript. - * - * @author David ‘Bombe’ Roden */ public class JavascriptFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/template/PostAccessor.java b/src/main/java/net/pterodactylus/sone/template/PostAccessor.java index 11cafea..4025c7b 100644 --- a/src/main/java/net/pterodactylus/sone/template/PostAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/PostAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - PostAccessor.java - Copyright © 2010–2016 David Roden + * Sone - PostAccessor.java - Copyright © 2010–2019 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 @@ -32,8 +32,6 @@ import com.google.common.collect.Collections2; *
    replies
    *
    All replies to this post, sorted by time, oldest first
    * - * - * @author David ‘Bombe’ Roden */ public class PostAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/ProfileAccessor.java b/src/main/java/net/pterodactylus/sone/template/ProfileAccessor.java index fafba86..a152038 100644 --- a/src/main/java/net/pterodactylus/sone/template/ProfileAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/ProfileAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - ProfileAccessor.java - Copyright © 2011–2016 David Roden + * Sone - ProfileAccessor.java - Copyright © 2011–2019 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 @@ -31,8 +31,6 @@ import net.pterodactylus.util.template.TemplateContext; * {@link Accessor} for {@link Profile} objects that overwrites the original * “avatar” member to include checks for whether the custom avatar should * actually be shown. - * - * @author David ‘Bombe’ Roden */ public class ProfileAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java index a3253b0..c6dea31 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - ReplyAccessor.java - Copyright © 2010–2016 David Roden + * Sone - ReplyAccessor.java - Copyright © 2010–2019 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 @@ -28,8 +28,6 @@ import net.pterodactylus.util.template.TemplateContext; /** * {@link Accessor} implementation that adds a couple of properties to * {@link Reply}s. - * - * @author David ‘Bombe’ Roden */ public class ReplyAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java index da12ca8..c093e6f 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java @@ -1,5 +1,5 @@ /* - * Sone - ReplyGroupFilter.java - Copyright © 2010–2016 David Roden + * Sone - ReplyGroupFilter.java - Copyright © 2010–2019 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 @@ -34,8 +34,6 @@ import net.pterodactylus.util.template.TemplateContext; * {@link Filter} implementation that groups replies by the post the are in * reply to, returning a map with the post as key and the list of replies as * values. - * - * @author David ‘Bombe’ Roden */ public class ReplyGroupFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/template/RequestChangeFilter.java b/src/main/java/net/pterodactylus/sone/template/RequestChangeFilter.java index 2d6167a..d004dfc 100644 --- a/src/main/java/net/pterodactylus/sone/template/RequestChangeFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/RequestChangeFilter.java @@ -1,5 +1,5 @@ /* - * Sone - RequestChangeFilter.java - Copyright © 2010–2016 David Roden + * Sone - RequestChangeFilter.java - Copyright © 2010–2019 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 @@ -34,8 +34,6 @@ import net.pterodactylus.util.template.TemplateContext; * This filter expects a {@link FreenetRequest} as input and outputs a * {@link URI} that is modified by the parameters. The name of the parameter is * handed in as “name”, the new value is stored in “value”. - * - * @author David ‘Bombe’ Roden */ public class RequestChangeFilter implements Filter { @@ -48,7 +46,7 @@ public class RequestChangeFilter implements Filter { String name = String.valueOf(parameters.get("name")); String value = String.valueOf(parameters.get("value")); - Map values = new HashMap(); + Map values = new HashMap<>(); Collection parameterNames = request.getHttpRequest().getParameterNames(); for (String parameterName : parameterNames) { values.put(parameterName, request.getHttpRequest().getParam(parameterName)); diff --git a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java index 5f4ab0c..a8cbe57 100644 --- a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - SoneAccessor.java - Copyright © 2010–2016 David Roden + * Sone - SoneAccessor.java - Copyright © 2010–2019 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 @@ -51,8 +51,6 @@ import net.pterodactylus.util.template.TemplateContext; *
    Will return {@code true} if the sone in question is the currently logged * in Sone.
    * - * - * @author David ‘Bombe’ Roden */ public class SoneAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java b/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java index f14d0ff..355b6a9 100644 --- a/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java @@ -1,5 +1,5 @@ /* - * Sone - SubstringFilter.java - Copyright © 2010–2016 David Roden + * Sone - SubstringFilter.java - Copyright © 2010–2019 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 @@ -28,8 +28,6 @@ import net.pterodactylus.util.template.TemplateContext; * “start” and “length.” “length” is optional and defaults to “the rest of the * string.” “start” starts at {@code 0} and can be negative to denote starting * at the end of the string. - * - * @author David ‘Bombe’ Roden */ public class SubstringFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java index 32650f1..26a128b 100644 --- a/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java @@ -1,5 +1,5 @@ /* - * Sone - TrustAccessor.java - Copyright © 2010–2016 David Roden + * Sone - TrustAccessor.java - Copyright © 2010–2019 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 @@ -30,8 +30,6 @@ import net.pterodactylus.util.template.TemplateContext; *
    {@link Boolean} that indicates whether this trust relationship has an * explicit value assigned to it.
    * - * - * @author David ‘Bombe’ Roden */ public class TrustAccessor extends ReflectionAccessor { diff --git a/src/main/java/net/pterodactylus/sone/template/UniqueElementFilter.java b/src/main/java/net/pterodactylus/sone/template/UniqueElementFilter.java index 2ca695b..6fb584e 100644 --- a/src/main/java/net/pterodactylus/sone/template/UniqueElementFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/UniqueElementFilter.java @@ -1,5 +1,5 @@ /* - * Sone - UniqueElementFilter.java - Copyright © 2011–2016 David Roden + * Sone - UniqueElementFilter.java - Copyright © 2011–2019 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 @@ -27,8 +27,6 @@ import net.pterodactylus.util.template.TemplateContext; /** * Filter that reduces a collection to a {@link Set}, removing duplicates. - * - * @author David ‘Bombe’ Roden */ public class UniqueElementFilter implements Filter { @@ -40,7 +38,7 @@ public class UniqueElementFilter implements Filter { if (!(data instanceof Collection)) { return data; } - return new HashSet((Collection) data); + return new HashSet<>((Collection) data); } } diff --git a/src/main/java/net/pterodactylus/sone/template/UnknownDateFilter.java b/src/main/java/net/pterodactylus/sone/template/UnknownDateFilter.java index 2c5a004..0d4872b 100644 --- a/src/main/java/net/pterodactylus/sone/template/UnknownDateFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/UnknownDateFilter.java @@ -1,5 +1,5 @@ /* - * Sone - UnknownDateFilter.java - Copyright © 2011–2016 David Roden + * Sone - UnknownDateFilter.java - Copyright © 2011–2019 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 @@ -26,8 +26,6 @@ import freenet.l10n.BaseL10n; /** * {@link Filter} implementation that replaces a {@link Long} with a value of * {@code 0} by a {@link String} from an {@link BaseL10n l10n handler}. - * - * @author David ‘Bombe’ Roden */ public class UnknownDateFilter implements Filter { diff --git a/src/main/java/net/pterodactylus/sone/text/FreemailPart.java b/src/main/java/net/pterodactylus/sone/text/FreemailPart.java index 69e6bfe..d45d99a 100644 --- a/src/main/java/net/pterodactylus/sone/text/FreemailPart.java +++ b/src/main/java/net/pterodactylus/sone/text/FreemailPart.java @@ -2,8 +2,6 @@ package net.pterodactylus.sone.text; /** * {@link Part} implementation that holds a freemail address. - * - * @author David ‘Bombe’ Roden */ public class FreemailPart implements Part { diff --git a/src/main/java/net/pterodactylus/sone/text/Parser.java b/src/main/java/net/pterodactylus/sone/text/Parser.java index f87b852..0daf30c 100644 --- a/src/main/java/net/pterodactylus/sone/text/Parser.java +++ b/src/main/java/net/pterodactylus/sone/text/Parser.java @@ -1,5 +1,5 @@ /* - * Sone - Parser.java - Copyright © 2010–2016 David Roden + * Sone - Parser.java - Copyright © 2010–2019 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 @@ -27,7 +27,6 @@ import javax.annotation.Nullable; * * @param * The type of the parser context - * @author David ‘Bombe’ Roden */ public interface Parser { diff --git a/src/main/java/net/pterodactylus/sone/text/ParserContext.java b/src/main/java/net/pterodactylus/sone/text/ParserContext.java index 7387967..056fcc1 100644 --- a/src/main/java/net/pterodactylus/sone/text/ParserContext.java +++ b/src/main/java/net/pterodactylus/sone/text/ParserContext.java @@ -1,5 +1,5 @@ /* - * Sone - ParserContext.java - Copyright © 2010–2016 David Roden + * Sone - ParserContext.java - Copyright © 2010–2019 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 @@ -21,8 +21,6 @@ package net.pterodactylus.sone.text; * Context for the {@link Parser}. This interface needs to be implemented by * {@link Parser}s that need to provide more information than just the text to * parse to {@link Parser#parse(String, ParserContext)}. - * - * @author David ‘Bombe’ Roden */ public interface ParserContext { diff --git a/src/main/java/net/pterodactylus/sone/text/PostPart.java b/src/main/java/net/pterodactylus/sone/text/PostPart.java index e70448f..de957c5 100644 --- a/src/main/java/net/pterodactylus/sone/text/PostPart.java +++ b/src/main/java/net/pterodactylus/sone/text/PostPart.java @@ -1,5 +1,5 @@ /* - * Sone - PostPart.java - Copyright © 2011–2016 David Roden + * Sone - PostPart.java - Copyright © 2011–2019 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 @@ -25,8 +25,6 @@ import net.pterodactylus.sone.data.Post; /** * {@link Part} implementation that stores a reference to a {@link Post}. - * - * @author David ‘Bombe’ Roden */ public class PostPart implements Part { diff --git a/src/main/java/net/pterodactylus/sone/text/SoneTextParserContext.java b/src/main/java/net/pterodactylus/sone/text/SoneTextParserContext.java index fba81ab..13a7a26 100644 --- a/src/main/java/net/pterodactylus/sone/text/SoneTextParserContext.java +++ b/src/main/java/net/pterodactylus/sone/text/SoneTextParserContext.java @@ -1,5 +1,5 @@ /* - * Sone - SoneTextParserContext.java - Copyright © 2011–2016 David Roden + * Sone - SoneTextParserContext.java - Copyright © 2011–2019 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 @@ -24,8 +24,6 @@ import net.pterodactylus.sone.web.page.FreenetRequest; * {@link ParserContext} implementation for the {@link SoneTextParser}. It * stores the {@link Sone} that provided the parsed text so that certain links * can be marked in a different way. - * - * @author David ‘Bombe’ Roden */ public class SoneTextParserContext implements ParserContext { diff --git a/src/main/java/net/pterodactylus/sone/text/TextFilter.java b/src/main/java/net/pterodactylus/sone/text/TextFilter.java index fa57f9c..0703f32 100644 --- a/src/main/java/net/pterodactylus/sone/text/TextFilter.java +++ b/src/main/java/net/pterodactylus/sone/text/TextFilter.java @@ -1,5 +1,5 @@ /* - * Sone - TextFilter.java - Copyright © 2011–2016 David Roden + * Sone - TextFilter.java - Copyright © 2011–2019 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 @@ -23,8 +23,6 @@ package net.pterodactylus.sone.text; * will be converted to “KSK@gpl.txt”. This will only work for links that point * to the same address Sone is accessed by, so if you access Sone using * localhost:8888, links to 127.0.0.1:8888 will not be removed. - * - * @author David ‘Bombe’ Roden */ public class TextFilter { diff --git a/src/main/java/net/pterodactylus/sone/utils/DefaultOption.java b/src/main/java/net/pterodactylus/sone/utils/DefaultOption.java index 0939f21..d9acaeb 100644 --- a/src/main/java/net/pterodactylus/sone/utils/DefaultOption.java +++ b/src/main/java/net/pterodactylus/sone/utils/DefaultOption.java @@ -7,7 +7,6 @@ import com.google.common.base.Predicate; * * @param * The type of the option - * @author David ‘Bombe’ Roden */ public class DefaultOption implements Option { diff --git a/src/main/java/net/pterodactylus/sone/utils/IntegerRangePredicate.java b/src/main/java/net/pterodactylus/sone/utils/IntegerRangePredicate.java index aac9594..1fd7527 100644 --- a/src/main/java/net/pterodactylus/sone/utils/IntegerRangePredicate.java +++ b/src/main/java/net/pterodactylus/sone/utils/IntegerRangePredicate.java @@ -1,5 +1,5 @@ /* - * Sone - IntegerRangePredicate.java - Copyright © 2013–2016 David Roden + * Sone - IntegerRangePredicate.java - Copyright © 2013–2019 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 @@ -23,8 +23,6 @@ import com.google.common.base.Predicate; * {@link Predicate} that verifies that an {@link Integer} value is not * {@code null} and is between a lower and an upper bound. Both bounds are * inclusive. - * - * @author David ‘Bombe’ Roden */ public class IntegerRangePredicate implements Predicate { diff --git a/src/main/java/net/pterodactylus/sone/utils/NumberParsers.java b/src/main/java/net/pterodactylus/sone/utils/NumberParsers.java index ce4da2f..471fc26 100644 --- a/src/main/java/net/pterodactylus/sone/utils/NumberParsers.java +++ b/src/main/java/net/pterodactylus/sone/utils/NumberParsers.java @@ -8,8 +8,6 @@ import com.google.common.primitives.Longs; /** * Parses numbers from strings. - * - * @author David ‘Bombe’ Roden */ public class NumberParsers { diff --git a/src/main/java/net/pterodactylus/sone/utils/Option.java b/src/main/java/net/pterodactylus/sone/utils/Option.java index 9149c07..eca96f5 100644 --- a/src/main/java/net/pterodactylus/sone/utils/Option.java +++ b/src/main/java/net/pterodactylus/sone/utils/Option.java @@ -5,7 +5,6 @@ package net.pterodactylus.sone.utils; * * @param * The type of the option - * @author David ‘Bombe’ Roden */ public interface Option { diff --git a/src/main/java/net/pterodactylus/sone/web/AllPages.kt b/src/main/java/net/pterodactylus/sone/web/AllPages.kt new file mode 100644 index 0000000..9eccccf --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/AllPages.kt @@ -0,0 +1,55 @@ +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 distrustPage: DistrustPage + @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 trustPage: TrustPage + @Inject lateinit var unbookmarkPage: UnbookmarkPage + @Inject lateinit var unfollowSonePage: UnfollowSonePage + @Inject lateinit var unlikePage: UnlikePage + @Inject lateinit var unlockSonePage: UnlockSonePage + @Inject lateinit var untrustPage: UntrustPage + @Inject lateinit var uploadImagePage: UploadImagePage + @Inject lateinit var viewPostPage: ViewPostPage + @Inject lateinit var viewSonePage: ViewSonePage + +} diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 6401b43..3d131c8 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -1,5 +1,5 @@ /* - * Sone - WebInterface.java - Copyright © 2010–2016 David Roden + * Sone - WebInterface.java - Copyright © 2010–2019 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 @@ -22,12 +22,10 @@ import static java.util.logging.Logger.getLogger; import static net.pterodactylus.util.template.TemplateParser.parse; import java.io.StringReader; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; @@ -61,49 +59,24 @@ import net.pterodactylus.sone.core.event.SoneLockedEvent; import net.pterodactylus.sone.core.event.SoneRemovedEvent; import net.pterodactylus.sone.core.event.SoneUnlockedEvent; import net.pterodactylus.sone.core.event.UpdateFoundEvent; -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.Profile; -import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.L10nFilter; -import net.pterodactylus.sone.freenet.wot.Identity; -import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.sone.main.Loaders; -import net.pterodactylus.sone.main.ReparseFilter; +import net.pterodactylus.sone.main.PluginHomepage; +import net.pterodactylus.sone.main.PluginVersion; +import net.pterodactylus.sone.main.PluginYear; import net.pterodactylus.sone.main.SonePlugin; -import net.pterodactylus.sone.main.SonePlugin.PluginHomepage; -import net.pterodactylus.sone.main.SonePlugin.PluginVersion; -import net.pterodactylus.sone.main.SonePlugin.PluginYear; import net.pterodactylus.sone.notify.ListNotification; import net.pterodactylus.sone.notify.ListNotificationFilter; import net.pterodactylus.sone.notify.PostVisibilityFilter; import net.pterodactylus.sone.notify.ReplyVisibilityFilter; -import net.pterodactylus.sone.template.AlbumAccessor; -import net.pterodactylus.sone.template.CollectionAccessor; -import net.pterodactylus.sone.template.CssClassNameFilter; -import net.pterodactylus.sone.template.HttpRequestAccessor; -import net.pterodactylus.sone.template.IdentityAccessor; -import net.pterodactylus.sone.template.ImageAccessor; -import net.pterodactylus.sone.template.ImageLinkFilter; -import net.pterodactylus.sone.template.JavascriptFilter; import net.pterodactylus.sone.template.LinkedElementRenderFilter; -import net.pterodactylus.sone.template.LinkedElementsFilter; import net.pterodactylus.sone.template.ParserFilter; -import net.pterodactylus.sone.template.PostAccessor; -import net.pterodactylus.sone.template.ProfileAccessor; import net.pterodactylus.sone.template.RenderFilter; -import net.pterodactylus.sone.template.ReplyAccessor; -import net.pterodactylus.sone.template.ReplyGroupFilter; -import net.pterodactylus.sone.template.RequestChangeFilter; import net.pterodactylus.sone.template.ShortenFilter; -import net.pterodactylus.sone.template.SoneAccessor; -import net.pterodactylus.sone.template.SubstringFilter; -import net.pterodactylus.sone.template.TrustAccessor; -import net.pterodactylus.sone.template.UniqueElementFilter; -import net.pterodactylus.sone.template.UnknownDateFilter; import net.pterodactylus.sone.text.Part; import net.pterodactylus.sone.text.SonePart; import net.pterodactylus.sone.text.SoneTextParser; @@ -139,8 +112,7 @@ import net.pterodactylus.sone.web.ajax.UnlikeAjaxPage; import net.pterodactylus.sone.web.ajax.UnlockSoneAjaxPage; import net.pterodactylus.sone.web.ajax.UntrustAjaxPage; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.sone.web.page.PageToadlet; -import net.pterodactylus.sone.web.page.PageToadletFactory; +import net.pterodactylus.sone.web.page.TemplateRenderer; import net.pterodactylus.sone.web.pages.AboutPage; import net.pterodactylus.sone.web.pages.BookmarkPage; import net.pterodactylus.sone.web.pages.BookmarksPage; @@ -160,10 +132,13 @@ import net.pterodactylus.sone.web.pages.EditAlbumPage; import net.pterodactylus.sone.web.pages.EditImagePage; import net.pterodactylus.sone.web.pages.EditProfileFieldPage; import net.pterodactylus.sone.web.pages.EditProfilePage; +import net.pterodactylus.sone.web.pages.EmptyAlbumTitlePage; +import net.pterodactylus.sone.web.pages.EmptyImageTitlePage; import net.pterodactylus.sone.web.pages.FollowSonePage; import net.pterodactylus.sone.web.pages.GetImagePage; import net.pterodactylus.sone.web.pages.ImageBrowserPage; import net.pterodactylus.sone.web.pages.IndexPage; +import net.pterodactylus.sone.web.pages.InvalidPage; import net.pterodactylus.sone.web.pages.KnownSonesPage; import net.pterodactylus.sone.web.pages.LikePage; import net.pterodactylus.sone.web.pages.LockSonePage; @@ -171,6 +146,7 @@ import net.pterodactylus.sone.web.pages.LoginPage; import net.pterodactylus.sone.web.pages.LogoutPage; import net.pterodactylus.sone.web.pages.MarkAsKnownPage; import net.pterodactylus.sone.web.pages.NewPage; +import net.pterodactylus.sone.web.pages.NoPermissionPage; import net.pterodactylus.sone.web.pages.OptionsPage; import net.pterodactylus.sone.web.pages.RescuePage; import net.pterodactylus.sone.web.pages.SearchPage; @@ -187,30 +163,15 @@ import net.pterodactylus.sone.web.pages.ViewSonePage; import net.pterodactylus.util.notify.Notification; import net.pterodactylus.util.notify.NotificationManager; import net.pterodactylus.util.notify.TemplateNotification; -import net.pterodactylus.util.template.CollectionSortFilter; -import net.pterodactylus.util.template.ContainsFilter; -import net.pterodactylus.util.template.DateFilter; -import net.pterodactylus.util.template.FormatFilter; -import net.pterodactylus.util.template.HtmlFilter; -import net.pterodactylus.util.template.MatchFilter; -import net.pterodactylus.util.template.ModFilter; -import net.pterodactylus.util.template.PaginationFilter; -import net.pterodactylus.util.template.ReflectionAccessor; -import net.pterodactylus.util.template.ReplaceFilter; -import net.pterodactylus.util.template.StoreFilter; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContextFactory; -import net.pterodactylus.util.template.TemplateProvider; -import net.pterodactylus.util.template.XmlFilter; import net.pterodactylus.util.web.RedirectPage; import net.pterodactylus.util.web.TemplatePage; import freenet.clients.http.SessionManager; import freenet.clients.http.SessionManager.Session; -import freenet.clients.http.ToadletContainer; import freenet.clients.http.ToadletContext; import freenet.l10n.BaseL10n; -import freenet.support.api.HTTPRequest; import com.google.common.base.Optional; import com.google.common.collect.Collections2; @@ -221,8 +182,6 @@ import com.google.inject.Inject; /** * Bundles functionality that a web interface of a Freenet plugin needs, e.g. * references to l10n helpers. - * - * @author David ‘Bombe’ Roden */ public class WebInterface implements SessionProvider { @@ -238,14 +197,12 @@ public class WebInterface implements SessionProvider { /** The Sone plugin. */ private final SonePlugin sonePlugin; - /** The registered toadlets. */ - private final List pageToadlets = new ArrayList(); - /** The form password. */ private final String formPassword; /** The template context factory. */ private final TemplateContextFactory templateContextFactory; + private final TemplateRenderer templateRenderer; /** The Sone text parser. */ private final SoneTextParser soneTextParser; @@ -262,7 +219,9 @@ public class WebInterface implements SessionProvider { private final ElementLoader elementLoader; private final LinkedElementRenderFilter linkedElementRenderFilter; private final TimeTextConverter timeTextConverter = new TimeTextConverter(); - private final L10nFilter l10nFilter = new L10nFilter(this); + private final L10nFilter l10nFilter; + + private final PageToadletRegistry pageToadletRegistry; /** The “new Sone” notification. */ private final ListNotification newSoneNotification; @@ -283,7 +242,7 @@ public class WebInterface implements SessionProvider { private final ListNotification mentionNotification; /** Notifications for sone inserts. */ - private final Map soneInsertNotifications = new HashMap(); + private final Map soneInsertNotifications = new HashMap<>(); /** Sone locked notification ticker objects. */ private final Map> lockedSonesTickerObjects = Collections.synchronizedMap(new HashMap>()); @@ -306,99 +265,68 @@ public class WebInterface implements SessionProvider { /** Scheduled executor for time-based notifications. */ private final ScheduledExecutorService ticker = Executors.newScheduledThreadPool(1); - /** - * Creates a new web interface. - * - * @param sonePlugin - * The Sone plugin - */ @Inject - public WebInterface(SonePlugin sonePlugin, Loaders loaders, ListNotificationFilter listNotificationFilter, PostVisibilityFilter postVisibilityFilter, ReplyVisibilityFilter replyVisibilityFilter, ElementLoader elementLoader) { + public WebInterface(SonePlugin sonePlugin, Loaders loaders, ListNotificationFilter listNotificationFilter, + PostVisibilityFilter postVisibilityFilter, ReplyVisibilityFilter replyVisibilityFilter, + ElementLoader elementLoader, TemplateContextFactory templateContextFactory, + TemplateRenderer templateRenderer, + ParserFilter parserFilter, ShortenFilter shortenFilter, + RenderFilter renderFilter, + LinkedElementRenderFilter linkedElementRenderFilter, + PageToadletRegistry pageToadletRegistry) { this.sonePlugin = sonePlugin; this.loaders = loaders; this.listNotificationFilter = listNotificationFilter; this.postVisibilityFilter = postVisibilityFilter; this.replyVisibilityFilter = replyVisibilityFilter; this.elementLoader = elementLoader; + this.templateRenderer = templateRenderer; + this.parserFilter = parserFilter; + this.shortenFilter = shortenFilter; + this.renderFilter = renderFilter; + this.linkedElementRenderFilter = linkedElementRenderFilter; + this.pageToadletRegistry = pageToadletRegistry; formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword(); soneTextParser = new SoneTextParser(getCore(), getCore()); + l10nFilter = new L10nFilter(getL10n()); - templateContextFactory = new TemplateContextFactory(); - templateContextFactory.addAccessor(Object.class, new ReflectionAccessor()); - templateContextFactory.addAccessor(Collection.class, new CollectionAccessor()); - templateContextFactory.addAccessor(Sone.class, new SoneAccessor(getCore(), new TimeTextConverter())); - templateContextFactory.addAccessor(Post.class, new PostAccessor(getCore())); - templateContextFactory.addAccessor(Reply.class, new ReplyAccessor(getCore())); - templateContextFactory.addAccessor(Album.class, new AlbumAccessor()); - templateContextFactory.addAccessor(Image.class, new ImageAccessor()); - templateContextFactory.addAccessor(Identity.class, new IdentityAccessor(getCore())); - templateContextFactory.addAccessor(Trust.class, new TrustAccessor()); - templateContextFactory.addAccessor(HTTPRequest.class, new HttpRequestAccessor()); - templateContextFactory.addAccessor(Profile.class, new ProfileAccessor(getCore())); - templateContextFactory.addFilter("date", new DateFilter()); - templateContextFactory.addFilter("html", new HtmlFilter()); - templateContextFactory.addFilter("replace", new ReplaceFilter()); - templateContextFactory.addFilter("store", new StoreFilter()); - templateContextFactory.addFilter("l10n", new L10nFilter(this)); - templateContextFactory.addFilter("substring", new SubstringFilter()); - templateContextFactory.addFilter("xml", new XmlFilter()); - templateContextFactory.addFilter("change", new RequestChangeFilter()); - templateContextFactory.addFilter("match", new MatchFilter()); - templateContextFactory.addFilter("css", new CssClassNameFilter()); - templateContextFactory.addFilter("js", new JavascriptFilter()); - templateContextFactory.addFilter("parse", parserFilter = new ParserFilter(getCore(), soneTextParser)); - templateContextFactory.addFilter("shorten", shortenFilter = new ShortenFilter()); - templateContextFactory.addFilter("render", renderFilter = new RenderFilter(getCore(), templateContextFactory)); - templateContextFactory.addFilter("linked-elements", new LinkedElementsFilter(elementLoader)); - templateContextFactory.addFilter("render-linked-element", linkedElementRenderFilter = new LinkedElementRenderFilter(templateContextFactory)); - templateContextFactory.addFilter("reparse", new ReparseFilter()); - templateContextFactory.addFilter("unknown", new UnknownDateFilter(getL10n(), "View.Sone.Text.UnknownDate")); - templateContextFactory.addFilter("format", new FormatFilter()); - templateContextFactory.addFilter("sort", new CollectionSortFilter()); - templateContextFactory.addFilter("image-link", new ImageLinkFilter(getCore(), templateContextFactory)); - templateContextFactory.addFilter("replyGroup", new ReplyGroupFilter()); - templateContextFactory.addFilter("in", new ContainsFilter()); - templateContextFactory.addFilter("unique", new UniqueElementFilter()); - templateContextFactory.addFilter("mod", new ModFilter()); - templateContextFactory.addFilter("paginate", new PaginationFilter()); - templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER); - templateContextFactory.addProvider(loaders.getTemplateProvider()); + this.templateContextFactory = templateContextFactory; templateContextFactory.addTemplateObject("webInterface", this); templateContextFactory.addTemplateObject("formPassword", formPassword); /* create notifications. */ Template newSoneNotificationTemplate = loaders.loadTemplate("/templates/notify/newSoneNotification.html"); - newSoneNotification = new ListNotification("new-sone-notification", "sones", newSoneNotificationTemplate, false); + 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); + newPostNotification = new ListNotification<>("new-post-notification", "posts", newPostNotificationTemplate, false); Template localPostNotificationTemplate = loaders.loadTemplate("/templates/notify/newPostNotification.html"); - localPostNotification = new ListNotification("local-post-notification", "posts", localPostNotificationTemplate, false); + localPostNotification = new ListNotification<>("local-post-notification", "posts", localPostNotificationTemplate, false); Template newReplyNotificationTemplate = loaders.loadTemplate("/templates/notify/newReplyNotification.html"); - newReplyNotification = new ListNotification("new-reply-notification", "replies", newReplyNotificationTemplate, false); + newReplyNotification = new ListNotification<>("new-reply-notification", "replies", newReplyNotificationTemplate, false); Template localReplyNotificationTemplate = loaders.loadTemplate("/templates/notify/newReplyNotification.html"); - localReplyNotification = new ListNotification("local-reply-notification", "replies", localReplyNotificationTemplate, false); + 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); + mentionNotification = new ListNotification<>("mention-notification", "posts", mentionNotificationTemplate, false); Template lockedSonesTemplate = loaders.loadTemplate("/templates/notify/lockedSonesNotification.html"); - lockedSonesNotification = new ListNotification("sones-locked-notification", "sones", lockedSonesTemplate); + lockedSonesNotification = new ListNotification<>("sones-locked-notification", "sones", lockedSonesTemplate); Template newVersionTemplate = loaders.loadTemplate("/templates/notify/newVersionNotification.html"); newVersionNotification = new TemplateNotification("new-version-notification", newVersionTemplate); Template insertingImagesTemplate = loaders.loadTemplate("/templates/notify/inserting-images-notification.html"); - insertingImagesNotification = new ListNotification("inserting-images-notification", "images", insertingImagesTemplate); + insertingImagesNotification = new ListNotification<>("inserting-images-notification", "images", insertingImagesTemplate); Template insertedImagesTemplate = loaders.loadTemplate("/templates/notify/inserted-images-notification.html"); - insertedImagesNotification = new ListNotification("inserted-images-notification", "images", insertedImagesTemplate); + insertedImagesNotification = new ListNotification<>("inserted-images-notification", "images", insertedImagesTemplate); Template imageInsertFailedTemplate = loaders.loadTemplate("/templates/notify/image-insert-failed-notification.html"); - imageInsertFailedNotification = new ListNotification("image-insert-failed-notification", "images", imageInsertFailedTemplate); + imageInsertFailedNotification = new ListNotification<>("image-insert-failed-notification", "images", imageInsertFailedTemplate); } // @@ -669,7 +597,7 @@ public class WebInterface implements SessionProvider { * Stops the web interface and unregisters all toadlets. */ public void stop() { - unregisterToadlets(); + pageToadletRegistry.unregisterToadlets(); ticker.shutdownNow(); } @@ -681,143 +609,93 @@ public class WebInterface implements SessionProvider { * Register all toadlets. */ private void registerToadlets() { - Template emptyTemplate = parse(new StringReader("")); - Template loginTemplate = loaders.loadTemplate("/templates/login.html"); - Template indexTemplate = loaders.loadTemplate("/templates/index.html"); - Template newTemplate = loaders.loadTemplate("/templates/new.html"); - Template knownSonesTemplate = loaders.loadTemplate("/templates/knownSones.html"); - Template createSoneTemplate = loaders.loadTemplate("/templates/createSone.html"); - Template createPostTemplate = loaders.loadTemplate("/templates/createPost.html"); - Template createReplyTemplate = loaders.loadTemplate("/templates/createReply.html"); - Template bookmarksTemplate = loaders.loadTemplate("/templates/bookmarks.html"); - Template searchTemplate = loaders.loadTemplate("/templates/search.html"); - Template editProfileTemplate = loaders.loadTemplate("/templates/editProfile.html"); - Template editProfileFieldTemplate = loaders.loadTemplate("/templates/editProfileField.html"); - Template deleteProfileFieldTemplate = loaders.loadTemplate("/templates/deleteProfileField.html"); - Template viewSoneTemplate = loaders.loadTemplate("/templates/viewSone.html"); - Template viewPostTemplate = loaders.loadTemplate("/templates/viewPost.html"); - Template deletePostTemplate = loaders.loadTemplate("/templates/deletePost.html"); - Template deleteReplyTemplate = loaders.loadTemplate("/templates/deleteReply.html"); - Template deleteSoneTemplate = loaders.loadTemplate("/templates/deleteSone.html"); - Template imageBrowserTemplate = loaders.loadTemplate("/templates/imageBrowser.html"); - Template createAlbumTemplate = loaders.loadTemplate("/templates/createAlbum.html"); - Template deleteAlbumTemplate = loaders.loadTemplate("/templates/deleteAlbum.html"); - Template deleteImageTemplate = loaders.loadTemplate("/templates/deleteImage.html"); - Template noPermissionTemplate = loaders.loadTemplate("/templates/noPermission.html"); - Template emptyImageTitleTemplate = loaders.loadTemplate("/templates/emptyImageTitle.html"); - Template emptyAlbumTitleTemplate = loaders.loadTemplate("/templates/emptyAlbumTitle.html"); - Template optionsTemplate = loaders.loadTemplate("/templates/options.html"); - Template rescueTemplate = loaders.loadTemplate("/templates/rescue.html"); - Template aboutTemplate = loaders.loadTemplate("/templates/about.html"); - Template invalidTemplate = loaders.loadTemplate("/templates/invalid.html"); Template postTemplate = loaders.loadTemplate("/templates/include/viewPost.html"); Template replyTemplate = loaders.loadTemplate("/templates/include/viewReply.html"); Template openSearchTemplate = loaders.loadTemplate("/templates/xml/OpenSearch.xml"); - PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/"); - pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage("", "index.html"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this, postVisibilityFilter), "Index")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new NewPage(newTemplate, this), "New")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateSonePage(createSoneTemplate, this), "CreateSone")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new KnownSonesPage(knownSonesTemplate, this), "KnownSones")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditProfilePage(editProfileTemplate, this), "EditProfile")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditProfileFieldPage(editProfileFieldTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteProfileFieldPage(deleteProfileFieldTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreatePostPage(createPostTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyPage(createReplyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new ViewSonePage(viewSoneTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new ViewPostPage(viewPostTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LikePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlikePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeletePostPage(deletePostTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteReplyPage(deleteReplyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LockSonePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSonePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSonePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSonePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new ImageBrowserPage(imageBrowserTemplate, this), "ImageBrowser")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateAlbumPage(createAlbumTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditAlbumPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteAlbumPage(deleteAlbumTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UploadImagePage(invalidTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditImagePage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteImagePage(deleteImageTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkAsKnownPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new BookmarkPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnbookmarkPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new BookmarksPage(bookmarksTemplate, this), "Bookmarks")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new SearchPage(searchTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteSonePage(deleteSoneTemplate, this), "DeleteSone")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LoginPage(loginTemplate, this), "Login")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LogoutPage(emptyTemplate, this), "Logout")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new OptionsPage(optionsTemplate, this), "Options")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new RescuePage(rescueTemplate, this), "Rescue")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new AboutPage(aboutTemplate, this, new PluginVersion(SonePlugin.getPluginVersion()), new PluginYear(SonePlugin.getYear()), new PluginHomepage(SonePlugin.getHomepage())), "About")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("noPermission.html", noPermissionTemplate, "Page.NoPermission.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("emptyImageTitle.html", emptyImageTitleTemplate, "Page.EmptyImageTitle.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("emptyAlbumTitle.html", emptyAlbumTitleTemplate, "Page.EmptyAlbumTitle.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(emptyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("invalid.html", invalidTemplate, "Page.Invalid.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("css/", "/static/css/", "text/css"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("javascript/", "/static/javascript/", "text/javascript"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("images/", "/static/images/", "image/png"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new TemplatePage("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetStatusAjaxPage(this, elementLoader, timeTextConverter, l10nFilter, TimeZone.getDefault()))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetNotificationsAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreatePostAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetReplyAjaxPage(this, replyTemplate))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetPostAjaxPage(this, postTemplate))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetLinkedElementAjaxPage(this, elementLoader, linkedElementRenderFilter))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTimesAjaxPage(this, timeTextConverter, l10nFilter, TimeZone.getDefault()))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkAsKnownAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeletePostAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteReplyAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LockSoneAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSoneAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSoneAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSoneAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditAlbumAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditImageAjaxPage(this, parserFilter, shortenFilter, renderFilter))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LikeAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlikeAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetLikesAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new BookmarkAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnbookmarkAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new EditProfileFieldAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteProfileFieldAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new MoveProfileFieldAjaxPage(this))); - - ToadletContainer toadletContainer = sonePlugin.pluginRespirator().getToadletContainer(); - toadletContainer.getPageMaker().addNavigationCategory("/Sone/index.html", "Navigation.Menu.Sone.Name", "Navigation.Menu.Sone.Tooltip", sonePlugin); - for (PageToadlet toadlet : pageToadlets) { - String menuName = toadlet.getMenuName(); - if (menuName != null) { - toadletContainer.register(toadlet, "Navigation.Menu.Sone.Name", toadlet.path(), true, "Navigation.Menu.Sone.Item." + menuName + ".Name", "Navigation.Menu.Sone.Item." + menuName + ".Tooltip", false, toadlet); - } else { - toadletContainer.register(toadlet, null, toadlet.path(), true, false); - } - } - } - - /** - * Unregisters all toadlets. - */ - private void unregisterToadlets() { - ToadletContainer toadletContainer = sonePlugin.pluginRespirator().getToadletContainer(); - for (PageToadlet pageToadlet : pageToadlets) { - toadletContainer.unregister(pageToadlet); - } - toadletContainer.getPageMaker().removeNavigationCategory("Navigation.Menu.Sone.Name"); + pageToadletRegistry.addPage(new RedirectPage("", "index.html")); + pageToadletRegistry.addPage(new IndexPage(this, loaders, templateRenderer, postVisibilityFilter)); + pageToadletRegistry.addPage(new NewPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new CreateSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new KnownSonesPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EditProfilePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EditProfileFieldPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeleteProfileFieldPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new CreatePostPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new CreateReplyPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new ViewSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new ViewPostPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new LikePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UnlikePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeletePostPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeleteReplyPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new LockSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UnlockSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new FollowSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UnfollowSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new ImageBrowserPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new CreateAlbumPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EditAlbumPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeleteAlbumPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UploadImagePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EditImagePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeleteImagePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new TrustPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DistrustPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UntrustPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new MarkAsKnownPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new BookmarkPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new UnbookmarkPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new BookmarksPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new SearchPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DeleteSonePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new LoginPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new LogoutPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new OptionsPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new RescuePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new AboutPage(this, loaders, templateRenderer, new PluginVersion(SonePlugin.getPluginVersion()), new PluginYear(sonePlugin.getYear()), new PluginHomepage(sonePlugin.getHomepage()))); + pageToadletRegistry.addPage(new InvalidPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new NoPermissionPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EmptyImageTitlePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new EmptyAlbumTitlePage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(new DismissNotificationPage(this, loaders, templateRenderer)); + pageToadletRegistry.addPage(loaders.loadStaticPage("css/", "/static/css/", "text/css")); + pageToadletRegistry.addPage(loaders.loadStaticPage("javascript/", "/static/javascript/", "text/javascript")); + pageToadletRegistry.addPage(loaders.loadStaticPage("images/", "/static/images/", "image/png")); + pageToadletRegistry.addPage(new TemplatePage("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate)); + pageToadletRegistry.addPage(new GetImagePage(this)); + pageToadletRegistry.addPage(new GetTranslationAjaxPage(this)); + pageToadletRegistry.addPage(new GetStatusAjaxPage(this, elementLoader, timeTextConverter, l10nFilter, TimeZone.getDefault())); + pageToadletRegistry.addPage(new GetNotificationsAjaxPage(this)); + pageToadletRegistry.addPage(new DismissNotificationAjaxPage(this)); + pageToadletRegistry.addPage(new CreatePostAjaxPage(this)); + pageToadletRegistry.addPage(new CreateReplyAjaxPage(this)); + pageToadletRegistry.addPage(new GetReplyAjaxPage(this, replyTemplate)); + pageToadletRegistry.addPage(new GetPostAjaxPage(this, postTemplate)); + pageToadletRegistry.addPage(new GetLinkedElementAjaxPage(this, elementLoader, linkedElementRenderFilter)); + pageToadletRegistry.addPage(new GetTimesAjaxPage(this, timeTextConverter, l10nFilter, TimeZone.getDefault())); + pageToadletRegistry.addPage(new MarkAsKnownAjaxPage(this)); + pageToadletRegistry.addPage(new DeletePostAjaxPage(this)); + pageToadletRegistry.addPage(new DeleteReplyAjaxPage(this)); + pageToadletRegistry.addPage(new LockSoneAjaxPage(this)); + pageToadletRegistry.addPage(new UnlockSoneAjaxPage(this)); + pageToadletRegistry.addPage(new FollowSoneAjaxPage(this)); + pageToadletRegistry.addPage(new UnfollowSoneAjaxPage(this)); + pageToadletRegistry.addPage(new EditAlbumAjaxPage(this)); + pageToadletRegistry.addPage(new EditImageAjaxPage(this, parserFilter, shortenFilter, renderFilter)); + pageToadletRegistry.addPage(new TrustAjaxPage(this)); + pageToadletRegistry.addPage(new DistrustAjaxPage(this)); + pageToadletRegistry.addPage(new UntrustAjaxPage(this)); + pageToadletRegistry.addPage(new LikeAjaxPage(this)); + pageToadletRegistry.addPage(new UnlikeAjaxPage(this)); + pageToadletRegistry.addPage(new GetLikesAjaxPage(this)); + pageToadletRegistry.addPage(new BookmarkAjaxPage(this)); + pageToadletRegistry.addPage(new UnbookmarkAjaxPage(this)); + pageToadletRegistry.addPage(new EditProfileFieldAjaxPage(this)); + pageToadletRegistry.addPage(new DeleteProfileFieldAjaxPage(this)); + pageToadletRegistry.addPage(new MoveProfileFieldAjaxPage(this)); + + pageToadletRegistry.registerToadlets(); } /** @@ -831,7 +709,7 @@ public class WebInterface implements SessionProvider { */ private Collection getMentionedSones(String text) { /* we need no context to find mentioned Sones. */ - Set mentionedSones = new HashSet(); + Set mentionedSones = new HashSet<>(); for (Part part : soneTextParser.parse(text, null)) { if (part instanceof SonePart) { mentionedSones.add(((SonePart) part).getSone()); diff --git a/src/main/java/net/pterodactylus/sone/web/page/FreenetPage.java b/src/main/java/net/pterodactylus/sone/web/page/FreenetPage.java deleted file mode 100644 index 813703c..0000000 --- a/src/main/java/net/pterodactylus/sone/web/page/FreenetPage.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Sone - FreenetPage.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.web.page; - -import java.net.URI; - -import net.pterodactylus.util.web.Page; - -/** - * Freenet-specific {@link Page} extension that adds the capability to allow a - * link to a page to be unharmed by Freenet’s content filter. - * - * @author David ‘Bombe’ Roden - */ -public interface FreenetPage extends Page { - - /** - * Returns whether the given should be excepted from being filtered. - * - * @param link - * The link to check - * @return {@code true} if the link should not be filtered, {@code false} if - * it should be filtered - */ - public boolean isLinkExcepted(URI link); - -} diff --git a/src/main/java/net/pterodactylus/sone/web/page/FreenetRequest.java b/src/main/java/net/pterodactylus/sone/web/page/FreenetRequest.java deleted file mode 100644 index ecbc0bb..0000000 --- a/src/main/java/net/pterodactylus/sone/web/page/FreenetRequest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Sone - FreenetRequest.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.web.page; - -import java.net.URI; - -import net.pterodactylus.util.web.Method; -import net.pterodactylus.util.web.Request; -import freenet.clients.http.ToadletContext; -import freenet.support.api.HTTPRequest; - -/** - * Encapsulates all Freenet-specific properties of a request. - * - * @author David ‘Bombe’ Roden - */ -public class FreenetRequest extends Request { - - /** The underlying HTTP request from Freenet. */ - private final HTTPRequest httpRequest; - - /** The toadlet context. */ - private final ToadletContext toadletContext; - - /** - * Creates a new freenet request. - * - * @param uri - * The URI that is being accessed - * @param method - * The method used to access this page - * @param httpRequest - * The underlying HTTP request from Freenet - * @param toadletContext - * The toadlet context - */ - public FreenetRequest(URI uri, Method method, HTTPRequest httpRequest, ToadletContext toadletContext) { - super(uri, method); - this.httpRequest = httpRequest; - this.toadletContext = toadletContext; - } - - // - // ACCESSORS - // - - /** - * Returns the underlying HTTP request from Freenet. - * - * @return The underlying HTTP request from Freenet - */ - public HTTPRequest getHttpRequest() { - return httpRequest; - } - - /** - * Returns the toadlet context. - * - * @return The toadlet context - */ - public ToadletContext getToadletContext() { - return toadletContext; - } - -} diff --git a/src/main/java/net/pterodactylus/sone/web/page/FreenetTemplatePage.java b/src/main/java/net/pterodactylus/sone/web/page/FreenetTemplatePage.java deleted file mode 100644 index 9cfd026..0000000 --- a/src/main/java/net/pterodactylus/sone/web/page/FreenetTemplatePage.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Sone - FreenetTemplatePage.java - Copyright © 2010–2016 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 . - */ - -package net.pterodactylus.sone.web.page; - -import static java.lang.String.format; -import static java.util.logging.Logger.getLogger; - -import java.io.IOException; -import java.io.StringWriter; -import java.net.URI; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import net.pterodactylus.util.template.Template; -import net.pterodactylus.util.template.TemplateContext; -import net.pterodactylus.util.template.TemplateContextFactory; -import net.pterodactylus.util.web.Method; -import net.pterodactylus.util.web.Page; -import net.pterodactylus.util.web.RedirectResponse; -import net.pterodactylus.util.web.Response; -import freenet.clients.http.LinkEnabledCallback; -import freenet.clients.http.PageMaker; -import freenet.clients.http.PageNode; -import freenet.clients.http.ToadletContext; -import freenet.support.HTMLNode; - -/** - * Base class for all {@link Page}s that are rendered with {@link Template}s and - * fit into Freenet’s web interface. - * - * @author David ‘Bombe’ Roden - */ -public class FreenetTemplatePage implements FreenetPage, LinkEnabledCallback { - - /** The logger. */ - private static final Logger logger = getLogger(FreenetTemplatePage.class.getName()); - - /** The path of the page. */ - private final String path; - - /** The template context factory. */ - private final TemplateContextFactory templateContextFactory; - - /** The template to render. */ - private final Template template; - - /** Where to redirect for invalid form passwords. */ - private final String invalidFormPasswordRedirectTarget; - - /** - * Creates a new template page. - * - * @param path - * The path of the page - * @param templateContextFactory - * The template context factory - * @param template - * The template to render - * @param invalidFormPasswordRedirectTarget - * The target to redirect to if a POST request does not contain - * the correct form password - */ - public FreenetTemplatePage(String path, TemplateContextFactory templateContextFactory, Template template, String invalidFormPasswordRedirectTarget) { - this.path = path; - this.templateContextFactory = templateContextFactory; - this.template = template; - this.invalidFormPasswordRedirectTarget = invalidFormPasswordRedirectTarget; - } - - /** - * {@inheritDoc} - */ - @Override - public String getPath() { - return path; - } - - /** - * Returns the title of the page. - * - * @param request - * The request to serve - * @return The title of the page - */ - @SuppressWarnings("static-method") - protected String getPageTitle(FreenetRequest request) { - return null; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isPrefixPage() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public final Response handleRequest(FreenetRequest request, Response response) throws IOException { - String redirectTarget = getRedirectTarget(request); - if (redirectTarget != null) { - return new RedirectResponse(redirectTarget); - } - - if (isFullAccessOnly() && !request.getToadletContext().isAllowedFullAccess()) { - return response.setStatusCode(401).setStatusText("Not authorized").setContentType("text/html"); - } - ToadletContext toadletContext = request.getToadletContext(); - if (request.getMethod() == Method.POST) { - /* require form password. */ - String formPassword = request.getHttpRequest().getPartAsStringFailsafe("formPassword", 32); - if (!formPassword.equals(toadletContext.getContainer().getFormPassword())) { - return new RedirectResponse(invalidFormPasswordRedirectTarget); - } - } - PageMaker pageMaker = toadletContext.getPageMaker(); - PageNode pageNode = pageMaker.getPageNode(getPageTitle(request), toadletContext); - for (String styleSheet : getStyleSheets()) { - pageNode.addCustomStyleSheet(styleSheet); - } - for (Map linkNodeParameters : getAdditionalLinkNodes(request)) { - HTMLNode linkNode = pageNode.headNode.addChild("link"); - for (Entry parameter : linkNodeParameters.entrySet()) { - linkNode.addAttribute(parameter.getKey(), parameter.getValue()); - } - } - String shortcutIcon = getShortcutIcon(); - if (shortcutIcon != null) { - pageNode.addForwardLink("icon", shortcutIcon); - } - - TemplateContext templateContext = templateContextFactory.createTemplateContext(); - templateContext.mergeContext(template.getInitialContext()); - try { - long start = System.nanoTime(); - processTemplate(request, templateContext); - long finish = System.nanoTime(); - logger.log(Level.FINEST, format("Template was rendered in %.2fms.", (finish - start) / 1000000.0)); - } catch (RedirectException re1) { - return new RedirectResponse(re1.getTarget()); - } - - StringWriter stringWriter = new StringWriter(); - template.render(templateContext, stringWriter); - pageNode.content.addChild("%", stringWriter.toString()); - - postProcess(request, templateContext); - - return response.setStatusCode(200).setStatusText("OK").setContentType("text/html").write(pageNode.outer.generate()); - } - - /** - * Can be overridden to return a custom set of style sheets that are to be - * included in the page’s header. - * - * @return Additional style sheets to load - */ - @SuppressWarnings("static-method") - protected Collection getStyleSheets() { - return Collections.emptySet(); - } - - /** - * Returns the name of the shortcut icon to include in the page’s header. - * - * @return The URL of the shortcut icon, or {@code null} for no icon - */ - @SuppressWarnings("static-method") - protected String getShortcutIcon() { - return null; - } - - /** - * Can be overridden when extending classes need to set variables in the - * template before it is rendered. - * - * @param request - * The request that is rendered - * @param templateContext - * The template context to set variables in - * @throws RedirectException - * if the processing page wants to redirect after processing - */ - protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { - /* do nothing. */ - } - - /** - * This method will be called after - * {@link #processTemplate(FreenetRequest, TemplateContext)} has processed - * the template and the template was rendered. This method will not be - * called if {@link #processTemplate(FreenetRequest, TemplateContext)} - * throws a {@link RedirectException}! - * - * @param request - * The request being processed - * @param templateContext - * The template context that supplied the rendered data - */ - protected void postProcess(FreenetRequest request, TemplateContext templateContext) { - /* do nothing. */ - } - - /** - * Can be overridden to redirect the user to a different page, in case a log - * in is required, or something else is wrong. - * - * @param request - * The request that is processed - * @return The URL to redirect to, or {@code null} to not redirect - */ - @SuppressWarnings("static-method") - protected String getRedirectTarget(FreenetRequest request) { - return null; - } - - /** - * Returns additional <link> nodes for the HTML’s <head> node. - * - * @param request - * The request for which to return the link nodes - * @return All link nodes that should be added to the HTML head - */ - @SuppressWarnings("static-method") - protected List> getAdditionalLinkNodes(FreenetRequest request) { - return Collections.emptyList(); - } - - /** - * Returns whether this page should only be allowed for requests from hosts - * with full access. - * - * @return {@code true} if this page should only be allowed for hosts with - * full access, {@code false} to allow this page for any host - */ - @SuppressWarnings("static-method") - protected boolean isFullAccessOnly() { - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isLinkExcepted(URI link) { - return false; - } - - // - // INTERFACE LinkEnabledCallback - // - - /** - * {@inheritDoc} - */ - @Override - public boolean isEnabled(ToadletContext toadletContext) { - return !isFullAccessOnly(); - } - - /** - * Exception that can be thrown to signal that a subclassed {@link Page} - * wants to redirect the user during the - * {@link FreenetTemplatePage#processTemplate(FreenetRequest, TemplateContext)} - * method call. - * - * @author David ‘Bombe’ Roden - */ - public static class RedirectException extends Exception { - - /** The target to redirect to. */ - private final String target; - - /** - * Creates a new redirect exception. - * - * @param target - * The target of the redirect - */ - public RedirectException(String target) { - this.target = target; - } - - /** - * Returns the target to redirect to. - * - * @return The target to redirect to - */ - public String getTarget() { - return target; - } - - @Override - public String toString() { - return format("RedirectException{target='%s'}", target); - } - - } - -} diff --git a/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java b/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java index 17a1bab..2b22377 100644 --- a/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java +++ b/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java @@ -1,5 +1,5 @@ /* - * Sone - PageToadlet.java - Copyright © 2010–2016 David Roden + * Sone - PageToadlet.java - Copyright © 2010–2019 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 @@ -30,19 +30,21 @@ import net.pterodactylus.util.web.Response; import freenet.client.HighLevelSimpleClient; import freenet.clients.http.LinkEnabledCallback; import freenet.clients.http.LinkFilterExceptedToadlet; +import freenet.clients.http.SessionManager; import freenet.clients.http.Toadlet; import freenet.clients.http.ToadletContext; import freenet.clients.http.ToadletContextClosedException; +import freenet.l10n.NodeL10n; import freenet.support.MultiValueTable; import freenet.support.api.HTTPRequest; /** * {@link Toadlet} implementation that is wrapped around a {@link Page}. - * - * @author David ‘Bombe’ Roden */ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFilterExceptedToadlet { + private final SessionManager sessionManager; + /** The name of the menu item. */ private final String menuName; @@ -65,8 +67,9 @@ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFil * Prefix that is prepended to all {@link Page#getPath()} return * values */ - protected PageToadlet(HighLevelSimpleClient highLevelSimpleClient, String menuName, Page page, String pathPrefix) { + protected PageToadlet(HighLevelSimpleClient highLevelSimpleClient, SessionManager sessionManager, String menuName, Page page, String pathPrefix) { super(highLevelSimpleClient); + this.sessionManager = sessionManager; this.menuName = menuName; this.page = page; this.pathPrefix = pathPrefix; @@ -104,7 +107,7 @@ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFil * if the toadlet context is closed */ public void handleMethodGET(URI uri, HTTPRequest httpRequest, ToadletContext toadletContext) throws IOException, ToadletContextClosedException { - handleRequest(new FreenetRequest(uri, Method.GET, httpRequest, toadletContext)); + handleRequest(new FreenetRequest(uri, Method.GET, httpRequest, toadletContext, NodeL10n.getBase(), sessionManager)); } /** @@ -122,7 +125,7 @@ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFil * if the toadlet context is closed */ public void handleMethodPOST(URI uri, HTTPRequest httpRequest, ToadletContext toadletContext) throws IOException, ToadletContextClosedException { - handleRequest(new FreenetRequest(uri, Method.POST, httpRequest, toadletContext)); + handleRequest(new FreenetRequest(uri, Method.POST, httpRequest, toadletContext, NodeL10n.getBase(), sessionManager)); } /** @@ -147,7 +150,7 @@ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFil try (AutoCloseableBucket pageBucket = new AutoCloseableBucket(pageRequest.getToadletContext().getBucketFactory().makeBucket(-1)); OutputStream pageBucketOutputStream = pageBucket.getBucket().getOutputStream()) { Response pageResponse = page.handleRequest(pageRequest, new Response(pageBucketOutputStream)); - MultiValueTable headers = new MultiValueTable(); + MultiValueTable headers = new MultiValueTable<>(); if (pageResponse.getHeaders() != null) { for (Header header : pageResponse.getHeaders()) { for (String value : header) { diff --git a/src/main/java/net/pterodactylus/sone/web/page/PageToadletFactory.java b/src/main/java/net/pterodactylus/sone/web/page/PageToadletFactory.java deleted file mode 100644 index da5fcde..0000000 --- a/src/main/java/net/pterodactylus/sone/web/page/PageToadletFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Sone - PageToadletFactory.java - Copyright © 2010–2016 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 . - */ - -package net.pterodactylus.sone.web.page; - -import net.pterodactylus.util.web.Page; -import freenet.client.HighLevelSimpleClient; - -/** - * Factory that creates {@link PageToadlet}s using a given - * {@link HighLevelSimpleClient}. - * - * @author David ‘Bombe’ Roden - */ -public class PageToadletFactory { - - /** The client to use when creating the toadlets. */ - private final HighLevelSimpleClient highLevelSimpleClient; - - /** The prefix for all pages’ paths. */ - private final String pathPrefix; - - /** - * Creates a new {@link PageToadlet} factory. - * - * @param highLevelSimpleClient - * The client to use when creating the toadlets - * @param pathPrefix - * The path that is prepended to all pages’ paths - */ - public PageToadletFactory(HighLevelSimpleClient highLevelSimpleClient, String pathPrefix) { - this.highLevelSimpleClient = highLevelSimpleClient; - this.pathPrefix = pathPrefix; - } - - /** - * Creates a {@link PageToadlet} that wraps the given page and does not - * appear in the node’s menu. - * - * @param page - * The page to wrap - * @return The toadlet wrapped around the page - */ - public PageToadlet createPageToadlet(Page page) { - return createPageToadlet(page, null); - } - - /** - * Creates a {@link PageToadlet} that wraps the given page and appears in - * the node’s menu under the given name. - * - * @param page - * The page to wrap - * @param menuName - * The name of the menu item - * @return The toadlet wrapped around the page - */ - public PageToadlet createPageToadlet(Page page, String menuName) { - return new PageToadlet(highLevelSimpleClient, menuName, page, pathPrefix); - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/Fetched.kt b/src/main/kotlin/net/pterodactylus/sone/core/Fetched.kt new file mode 100644 index 0000000..1f48e3e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/Fetched.kt @@ -0,0 +1,9 @@ +package net.pterodactylus.sone.core + +import freenet.client.FetchResult +import freenet.keys.FreenetURI + +/** + * Container for a fetched URI and the [FetchResult]. + */ +data class Fetched(val freenetUri: FreenetURI, val fetchResult: FetchResult) diff --git a/src/main/kotlin/net/pterodactylus/sone/core/Preferences.kt b/src/main/kotlin/net/pterodactylus/sone/core/Preferences.kt new file mode 100644 index 0000000..783552e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/Preferences.kt @@ -0,0 +1,141 @@ +/* + * Sone - Preferences.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.core + +import com.google.common.base.Predicates.* +import com.google.common.eventbus.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.fcp.FcpInterface.* +import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.* +import net.pterodactylus.sone.fcp.event.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.utils.IntegerRangePredicate.* +import net.pterodactylus.util.config.* +import java.lang.Integer.* + +/** + * Convenience interface for external classes that want to access the core’s + * configuration. + */ +class Preferences(private val eventBus: EventBus) { + + private val _insertionDelay = DefaultOption(60, range(0, MAX_VALUE)) + val insertionDelay: Int get() = _insertionDelay.get() + var newInsertionDelay: Int? + get() = unsupported + set(value) { + _insertionDelay.set(value) + eventBus.post(InsertionDelayChangedEvent(insertionDelay)) + eventBus.post(PreferenceChangedEvent("InsertionDelay", insertionDelay)) + } + + private val _postsPerPage = DefaultOption(10, range(1, MAX_VALUE)) + val postsPerPage: Int get() = _postsPerPage.get() + var newPostsPerPage: Int? + get() = unsupported + set(value) { + _postsPerPage.set(value) + eventBus.post(PreferenceChangedEvent("PostsPerPage", postsPerPage)) + } + + private val _imagesPerPage = DefaultOption(9, range(1, MAX_VALUE)) + val imagesPerPage: Int get() = _imagesPerPage.get() + var newImagesPerPage: Int? + get() = unsupported + set (value: Int?) = _imagesPerPage.set(value) + + private val _charactersPerPost = DefaultOption(400, or(range(50, MAX_VALUE), equalTo(-1))) + val charactersPerPost: Int get() = _charactersPerPost.get() + var newCharactersPerPost: Int? + get() = unsupported + set(value) = _charactersPerPost.set(value) + + private val _postCutOffLength = DefaultOption(200, range(50, MAX_VALUE)) + val postCutOffLength: Int get() = _postCutOffLength.get() + var newPostCutOffLength: Int? + get() = unsupported + set(value) = _postCutOffLength.set(value) + + private val _requireFullAccess = DefaultOption(false) + val requireFullAccess: Boolean get() = _requireFullAccess.get() + var newRequireFullAccess: Boolean? + get() = unsupported + set(value) = _requireFullAccess.set(value) + + private val _positiveTrust = DefaultOption(75, range(0, 100)) + val positiveTrust: Int get() = _positiveTrust.get() + var newPositiveTrust: Int? + get() = unsupported + set(value) = _positiveTrust.set(value) + + private val _negativeTrust = DefaultOption(-25, range(-100, 100)) + val negativeTrust: Int get() = _negativeTrust.get() + var newNegativeTrust: Int? + get() = unsupported + set(value) = _negativeTrust.set(value) + + private val _trustComment = DefaultOption("Set from Sone Web Interface") + val trustComment: String get() = _trustComment.get() + var newTrustComment: String? + get() = unsupported + set(value) = _trustComment.set(value) + + private val _fcpInterfaceActive = DefaultOption(false) + val fcpInterfaceActive: Boolean get() = _fcpInterfaceActive.get() + var newFcpInterfaceActive: Boolean? + get() = unsupported + set(value) { + _fcpInterfaceActive.set(value) + when (value) { + true -> eventBus.post(FcpInterfaceActivatedEvent()) + else -> eventBus.post(FcpInterfaceDeactivatedEvent()) + } + } + + private val _fcpFullAccessRequired = DefaultOption(ALWAYS) + val fcpFullAccessRequired: FullAccessRequired get() = _fcpFullAccessRequired.get() + var newFcpFullAccessRequired: FullAccessRequired? + get() = unsupported + set(value) { + _fcpFullAccessRequired.set(value) + eventBus.post(FullAccessRequiredChanged(fcpFullAccessRequired)) + } + + @Throws(ConfigurationException::class) + fun saveTo(configuration: Configuration) { + configuration.getIntValue("Option/ConfigurationVersion").value = 0 + configuration.getIntValue("Option/InsertionDelay").value = _insertionDelay.real + configuration.getIntValue("Option/PostsPerPage").value = _postsPerPage.real + configuration.getIntValue("Option/ImagesPerPage").value = _imagesPerPage.real + configuration.getIntValue("Option/CharactersPerPost").value = _charactersPerPost.real + configuration.getIntValue("Option/PostCutOffLength").value = _postCutOffLength.real + configuration.getBooleanValue("Option/RequireFullAccess").value = _requireFullAccess.real + configuration.getIntValue("Option/PositiveTrust").value = _positiveTrust.real + configuration.getIntValue("Option/NegativeTrust").value = _negativeTrust.real + configuration.getStringValue("Option/TrustComment").value = _trustComment.real + configuration.getBooleanValue("Option/ActivateFcpInterface").value = _fcpInterfaceActive.real + configuration.getIntValue("Option/FcpFullAccessRequired").value = toInt(_fcpFullAccessRequired.real) + } + + private fun toInt(fullAccessRequired: FullAccessRequired?): Int? { + return fullAccessRequired?.ordinal + } + +} + +private val unsupported: Nothing get() = throw UnsupportedOperationException() diff --git a/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt new file mode 100644 index 0000000..9a67f80 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt @@ -0,0 +1,12 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* + +class SoneComparison(private val oldSone: Sone, private val newSone: Sone) { + + val newPosts: Collection get() = newSone.posts - oldSone.posts + val removedPosts: Collection get() = oldSone.posts - newSone.posts + val newPostReplies: Collection get() = newSone.replies - oldSone.replies + val removedPostReplies: Collection get() = oldSone.replies - newSone.replies + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt new file mode 100644 index 0000000..28bac6d --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt @@ -0,0 +1,70 @@ +package net.pterodactylus.sone.core + +import com.google.common.eventbus.* +import com.google.inject.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Sone.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.logging.* +import javax.inject.Inject + +/** + * An `UpdatedSoneProcessor` is called to process a [Sone] after it has been + * downloaded from Freenet. + */ +@ImplementedBy(DefaultUpdateSoneProcessor::class) +interface UpdatedSoneProcessor { + + fun updateSone(sone: Sone) + +} + +abstract class BasicUpdateSoneProcessor(private val database: Database, private val eventBus: EventBus) : + UpdatedSoneProcessor { + + private val logger = Logging.getLogger(UpdatedSoneProcessor::javaClass.name)!! + + override fun updateSone(sone: Sone) { + val storedSone = database.getSone(sone.id) ?: return + if (!soneCanBeUpdated(storedSone, sone)) { + logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.") + return + } + + SoneComparison(storedSone, sone).apply { + newPosts + .onEach { post -> if (post.time <= sone.followingTime) post.isKnown = true } + .mapNotNull { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } } + .forEach(eventBus::post) + removedPosts + .map { PostRemovedEvent(it) } + .forEach(eventBus::post) + newPostReplies + .onEach { postReply -> if (postReply.time <= sone.followingTime) postReply.isKnown = true } + .mapNotNull { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } } + .forEach(eventBus::post) + removedPostReplies + .map { PostReplyRemovedEvent(it) } + .forEach(eventBus::post) + } + database.storeSone(sone) + sone.options = storedSone.options + sone.isKnown = storedSone.isKnown + sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown + } + + protected abstract fun soneCanBeUpdated(storedSone: Sone, newSone: Sone): Boolean + + private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0 + +} + +class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) : + BasicUpdateSoneProcessor(database, eventBus) { + + override fun soneCanBeUpdated(storedSone: Sone, newSone: Sone) = + newSone.time > storedSone.time + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.kt new file mode 100644 index 0000000..b2909f2 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/event/InsertionDelayChangedEvent.kt @@ -0,0 +1,3 @@ +package net.pterodactylus.sone.core.event + +data class InsertionDelayChangedEvent(val insertionDelay: Int) diff --git a/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostFoundEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostFoundEvent.kt new file mode 100644 index 0000000..ba7f957 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostFoundEvent.kt @@ -0,0 +1,30 @@ +/* + * Sone - NewPostFoundEvent.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.core.event + +import net.pterodactylus.sone.data.Post + +/** + * Event that signals that a new post was found. + */ +data class NewPostFoundEvent(val post: Post) { + + @Deprecated(message = "will go away", replaceWith = ReplaceWith("post")) + fun post() = post + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.kt new file mode 100644 index 0000000..a70d1b9 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/event/NewPostReplyFoundEvent.kt @@ -0,0 +1,30 @@ +/* + * Sone - NewPostReplyFoundEvent.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.core.event + +import net.pterodactylus.sone.data.PostReply + +/** + * Event that signals that a new [PostReply] was found. + */ +data class NewPostReplyFoundEvent(val postReply: PostReply) { + + @Deprecated(message = "will go away", replaceWith = ReplaceWith("postReply")) + fun postReply() = postReply + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/event/PostRemovedEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/event/PostRemovedEvent.kt new file mode 100644 index 0000000..117d800 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/event/PostRemovedEvent.kt @@ -0,0 +1,30 @@ +/* + * Sone - PostRemovedEvent.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.core.event + +import net.pterodactylus.sone.data.Post + +/** + * Event that signals that a [Post] was removed. + */ +data class PostRemovedEvent(val post: Post) { + + @Deprecated(message = "will go away", replaceWith = ReplaceWith("post")) + fun post() = post + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.kt b/src/main/kotlin/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.kt new file mode 100644 index 0000000..6aa495b --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/event/PostReplyRemovedEvent.kt @@ -0,0 +1,30 @@ +/* + * Sone - PostReplyRemovedEvent.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.core.event + +import net.pterodactylus.sone.data.PostReply + +/** + * Event that signals that a [PostReply] was removed. + */ +data class PostReplyRemovedEvent(val postReply: PostReply) { + + @Deprecated(message = "will go away", replaceWith = ReplaceWith("postReply")) + fun postReply() = postReply + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/data/Fingerprintable.kt b/src/main/kotlin/net/pterodactylus/sone/data/Fingerprintable.kt new file mode 100644 index 0000000..97a54f8 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/data/Fingerprintable.kt @@ -0,0 +1,29 @@ +/* + * Sone - Fingerprintable.kt - Copyright © 2011–2019 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 . + */ + +package net.pterodactylus.sone.data + +/** + * Interface for objects that can create a fingerprint of themselves, e.g. to + * detect modifications. The fingerprint should only contain original + * information; derived information should not be included. + */ +interface Fingerprintable { + + val fingerprint: String + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/data/Identified.kt b/src/main/kotlin/net/pterodactylus/sone/data/Identified.kt new file mode 100644 index 0000000..1cbad81 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/data/Identified.kt @@ -0,0 +1,27 @@ +/* + * Sone - Identified.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.data + +/** + * Interface for all objects that expose an ID. + */ +interface Identified { + + val id: String + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilder.kt new file mode 100644 index 0000000..acace46 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilder.kt @@ -0,0 +1,35 @@ +/* + * Sone - AlbumBuilder.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Album +import net.pterodactylus.sone.data.Sone + +/** + * Builder for [Album] objects. + */ +interface AlbumBuilder { + + fun randomId(): AlbumBuilder + fun withId(id: String): AlbumBuilder + + fun by(sone: Sone): AlbumBuilder + + fun build(): Album + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilderFactory.kt new file mode 100644 index 0000000..f153f33 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/AlbumBuilderFactory.kt @@ -0,0 +1,27 @@ +/* + * Sone - AlbumBuilderFactory.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database + +/** + * Factory for [AlbumBuilder]s. + */ +interface AlbumBuilderFactory { + + fun newAlbumBuilder(): AlbumBuilder + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/AlbumDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/AlbumDatabase.kt new file mode 100644 index 0000000..e61d429 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/AlbumDatabase.kt @@ -0,0 +1,24 @@ +/* + * Sone - AlbumDatabase.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database + +/** + * Combines an [AlbumProvider] and an [AlbumStore] into an album + * database. + */ +interface AlbumDatabase : AlbumProvider, AlbumBuilderFactory, AlbumStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/AlbumProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/AlbumProvider.kt new file mode 100644 index 0000000..db0146d --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/AlbumProvider.kt @@ -0,0 +1,29 @@ +/* + * Sone - AlbumProvider.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.* + +/** + * Interface for objects that can provide [Album]s by their ID. + */ +interface AlbumProvider { + + fun getAlbum(albumId: String): Album? + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/AlbumStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/AlbumStore.kt new file mode 100644 index 0000000..ddc7bb2 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/AlbumStore.kt @@ -0,0 +1,30 @@ +/* + * Sone - AlbumStore.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Album + +/** + * Interface for a store of albums. + */ +interface AlbumStore { + + fun storeAlbum(album: Album) + fun removeAlbum(album: Album) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/Database.kt b/src/main/kotlin/net/pterodactylus/sone/database/Database.kt index 522ce32..17337e2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/Database.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/Database.kt @@ -1,5 +1,5 @@ /* - * Sone - Database.java - Copyright © 2013–2016 David Roden + * Sone - Database.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt index f56f2f7..90b4f5e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt @@ -9,5 +9,6 @@ interface FriendProvider { fun getFriends(localSone: Sone): Collection fun isFriend(localSone: Sone, friendSoneId: String): Boolean + fun getFollowingTime(friendSoneId: String): Long? } diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt index 5ceb28e..c9ddbaa 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt @@ -1,5 +1,5 @@ /* - * Sone - ImageBuilder.java - Copyright © 2013–2016 David Roden + * Sone - ImageBuilder.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt index bae797c..f9f8be7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt @@ -1,5 +1,5 @@ /* - * Sone - ImageBuilderFactory.java - Copyright © 2013–2016 David Roden + * Sone - ImageBuilderFactory.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt index 4617cef..b55c073 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt @@ -1,5 +1,5 @@ /* - * Sone - ImageDatabase.java - Copyright © 2013–2016 David Roden + * Sone - ImageDatabase.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt index c7cc75e..0cde52a 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt @@ -1,5 +1,5 @@ /* - * Sone - ImageProvider.java - Copyright © 2013–2016 David Roden + * Sone - ImageProvider.kt - Copyright © 2013–2019 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 @@ -17,9 +17,7 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.data.Image - -import com.google.common.base.Optional +import net.pterodactylus.sone.data.* /** * Provides [Image]s. diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt index 91cff2d..4be9dd9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt @@ -1,5 +1,5 @@ /* - * Sone - ImageStore.java - Copyright © 2013–2016 David Roden + * Sone - ImageStore.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt index c1377ca..542bf78 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt @@ -1,5 +1,5 @@ /* - * Sone - PostBuilder.java - Copyright © 2013–2016 David Roden + * Sone - PostBuilder.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt index d7604c3..e20248f 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt @@ -1,5 +1,5 @@ /* - * Sone - PostBuilderFactory.java - Copyright © 2013–2016 David Roden + * Sone - PostBuilderFactory.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt index 7b97c6a..02b9fd1 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt @@ -1,5 +1,5 @@ /* - * Sone - PostDatabase.java - Copyright © 2013–2016 David Roden + * Sone - PostDatabase.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt index 37cb2a1..abf7ab9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt @@ -1,5 +1,5 @@ /* - * Sone - PostProvider.java - Copyright © 2011–2016 David Roden + * Sone - PostProvider.kt - Copyright © 2011–2019 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 @@ -17,11 +17,9 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.database.memory.MemoryDatabase - -import com.google.common.base.Optional -import com.google.inject.ImplementedBy +import com.google.inject.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.database.memory.* /** * Interface for objects that can provide [Post]s by their ID. diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt index 0c333da..d8d7f8d 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt @@ -1,5 +1,5 @@ /* - * Sone - PostReplyBuilder.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyBuilder.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt index d039cda..50b58e8 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt @@ -1,5 +1,5 @@ /* - * Sone - PostReplyBuilderFactory.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyBuilderFactory.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt index 8f08cf3..316c772 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt @@ -1,5 +1,5 @@ /* - * Sone - PostReplyDatabase.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyDatabase.kt - Copyright © 2013–2019 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 diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt index 7e09017..cc797d7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt @@ -1,5 +1,5 @@ /* - * Sone - PostReplyProvider.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyProvider.kt - Copyright © 2013–2019 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 @@ -17,8 +17,7 @@ package net.pterodactylus.sone.database -import com.google.common.base.Optional -import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.data.* /** * Interface for objects that can provide [PostReply]s. diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt index 08ba380..f4839b1 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt @@ -1,5 +1,5 @@ /* - * Sone - PostReplyStore.java - Copyright © 2013–2016 David Roden + * Sone - PostReplyStore.kt - Copyright © 2013–2019 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 @@ -17,8 +17,7 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.* /** * Defines a store for [post replies][PostReply]. diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt index 3cb5f17..84ea39e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt @@ -1,5 +1,5 @@ /* - * Sone - PostStore.java - Copyright © 2013–2016 David Roden + * Sone - PostStore.kt - Copyright © 2013–2019 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 @@ -17,8 +17,7 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.* /** * Interface for a store for posts. diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt index 1aa6039..bfc74ac 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt @@ -1,5 +1,5 @@ /* - * Sone - ReplyBuilder.java - Copyright © 2013–2016 David Roden + * Sone - ReplyBuilder.kt - Copyright © 2013–2019 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 @@ -17,8 +17,7 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.data.Reply -import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.* /** * Methods that all reply builders need to implement in order to be able to diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt index b8ce5e1..4156d66 100644 --- a/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt @@ -1,5 +1,5 @@ /* - * Sone - SoneProvider.java - Copyright © 2011–2016 David Roden + * Sone - SoneProvider.kt - Copyright © 2011–2019 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 @@ -17,12 +17,9 @@ package net.pterodactylus.sone.database -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Sone - -import com.google.common.base.Function -import com.google.common.base.Optional -import com.google.inject.ImplementedBy +import com.google.inject.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* /** * Interface for objects that can provide [Sone]s by their ID. diff --git a/src/main/kotlin/net/pterodactylus/sone/fcp/AbstractSoneCommand.kt b/src/main/kotlin/net/pterodactylus/sone/fcp/AbstractSoneCommand.kt new file mode 100644 index 0000000..915c536 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/fcp/AbstractSoneCommand.kt @@ -0,0 +1,148 @@ +/* + * Sone - AbstractSoneCommand.kt - Copyright © 2011–2019 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 . + */ + +package net.pterodactylus.sone.fcp + +import com.google.common.base.Optional +import freenet.node.FSParseException +import freenet.support.SimpleFieldSet +import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder +import net.pterodactylus.sone.freenet.fcp.AbstractCommand +import net.pterodactylus.sone.freenet.fcp.Command +import net.pterodactylus.sone.freenet.fcp.FcpException +import net.pterodactylus.sone.template.SoneAccessor +import net.pterodactylus.sone.utils.asOptional +import net.pterodactylus.sone.utils.let +import net.pterodactylus.sone.utils.throwOnNullIf + +/** + * Abstract base implementation of a [Command] with Sone-related helper + * methods. + */ +abstract class AbstractSoneCommand +@JvmOverloads protected constructor( + protected val core: Core, + @get:JvmName("requiresWriteAccess") + val requiresWriteAccess: Boolean = false) : AbstractCommand() { + + @Throws(FcpException::class) + protected fun getSone(simpleFieldSet: SimpleFieldSet, parameterName: String, localOnly: Boolean): Sone = + getSone(simpleFieldSet, parameterName, localOnly, true).get() + + @Throws(FcpException::class) + protected fun getSone(simpleFieldSet: SimpleFieldSet, parameterName: String, localOnly: Boolean, mandatory: Boolean): Optional { + val soneId = simpleFieldSet.get(parameterName) + .throwOnNullIf(mandatory) { FcpException("Could not load Sone ID from “$parameterName”.") } + ?: return Optional.absent() + val sone = core.getSone(soneId) + if (mandatory && sone == null || sone != null && localOnly && !sone.isLocal) { + throw FcpException("Could not load Sone from “$soneId”.") + } + return sone.asOptional() + } + + @Throws(FcpException::class) + protected fun getPost(simpleFieldSet: SimpleFieldSet, parameterName: String): Post { + try { + val postId = simpleFieldSet.getString(parameterName) + return core.getPost(postId) + ?: throw FcpException("Could not load post from “$postId”.") + } catch (fspe1: FSParseException) { + throw FcpException("Could not post ID from “$parameterName”.", fspe1) + } + } + + @Throws(FcpException::class) + protected fun getReply(simpleFieldSet: SimpleFieldSet, parameterName: String): PostReply { + try { + val replyId = simpleFieldSet.getString(parameterName) + return core.getPostReply(replyId) + ?: throw FcpException("Could not load reply from “$replyId”.") + } catch (fspe1: FSParseException) { + throw FcpException("Could not reply ID from “$parameterName”.", fspe1) + } + } + + protected fun encodePost(post: Post, prefix: String, includeReplies: Boolean): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "ID", post.id) + put(prefix + "Sone", post.sone.id) + post.recipientId.let { put(prefix + "Recipient", it) } + put(prefix + "Time", post.time) + put(prefix + "Text", encodeString(post.text)) + put(encodeLikes(core.getLikes(post), "${prefix}Likes.")) + if (includeReplies) { + val replies = core.getReplies(post.id) + put(encodeReplies(replies, prefix)) + } + }.get() + + protected fun encodePosts(posts: Collection, prefix: String, includeReplies: Boolean): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "Count", posts.size) + posts.forEachIndexed { postIndex, post -> + put(encodePost(post, "$prefix$postIndex.", includeReplies)) + } + }.get() + + private fun encodeReplies(replies: Collection, prefix: String): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "Replies.Count", replies.size) + replies.forEachIndexed { replyIndex, reply -> + val replyPrefix = "${prefix}Replies.$replyIndex." + put(replyPrefix + "ID", reply.id) + put(replyPrefix + "Sone", reply.sone.id) + put(replyPrefix + "Time", reply.time) + put(replyPrefix + "Text", encodeString(reply.text)) + put(encodeLikes(core.getLikes(reply), "${replyPrefix}Likes.")) + } + }.get() + + override fun toString() = "${javaClass.name}[requiresWriteAccess=$requiresWriteAccess]" +} + +fun encodeString(text: String) = text + .replace("\\\\".toRegex(), "\\\\\\\\") + .replace("\n".toRegex(), "\\\\n") + .replace("\r".toRegex(), "\\\\r") + +fun encodeSone(sone: Sone, prefix: String, localSone: Optional): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "ID", sone.id) + put(prefix + "Name", sone.name) + put(prefix + "NiceName", SoneAccessor.getNiceName(sone)) + put(prefix + "LastUpdated", sone.time) + localSone.let { put(prefix + "Followed", it.hasFriend(sone.id).toString()) } + val profile = sone.profile + put(prefix + "Field.Count", profile.fields.size) + profile.fields.forEachIndexed { fieldIndex, field -> + put(prefix + "Field." + fieldIndex + ".Name", field.name) + put(prefix + "Field." + fieldIndex + ".Value", field.value) + } +}.get() + +fun encodeSones(sones: Collection, prefix: String): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "Count", sones.size) + sones.forEachIndexed { soneIndex, sone -> + put(encodeSone(sone, "$prefix$soneIndex.", Optional.absent())) + } +}.get() + +fun encodeLikes(likes: Collection, prefix: String): SimpleFieldSet = SimpleFieldSetBuilder().apply { + put(prefix + "Count", likes.size) + likes.forEachIndexed { index, sone -> put("$prefix$index.ID", sone.id) } +}.get() diff --git a/src/main/kotlin/net/pterodactylus/sone/main/FreenetModule.kt b/src/main/kotlin/net/pterodactylus/sone/main/FreenetModule.kt index a8da595..9b5fa2e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/main/FreenetModule.kt +++ b/src/main/kotlin/net/pterodactylus/sone/main/FreenetModule.kt @@ -1,25 +1,28 @@ package net.pterodactylus.sone.main -import com.google.inject.Binder -import com.google.inject.Module -import com.google.inject.Provides -import freenet.client.HighLevelSimpleClient -import freenet.node.Node -import freenet.pluginmanager.PluginRespirator +import com.google.inject.* +import freenet.client.* +import freenet.clients.http.* +import freenet.node.* +import freenet.pluginmanager.* +import javax.inject.Provider import javax.inject.Singleton /** * Guice [Module] that supplies some objects that are in fact supplied by the Freenet node. */ -class FreenetModule(private val pluginRespirator: PluginRespirator): Module { +class FreenetModule(private val pluginRespirator: PluginRespirator) : Module { override fun configure(binder: Binder): Unit = binder.run { - bind(PluginRespirator::class.java).toProvider { pluginRespirator } - pluginRespirator.node!!.let { node -> bind(Node::class.java).toProvider { node } } - bind(HighLevelSimpleClient::class.java).toProvider { pluginRespirator.hlSimpleClient!! } + bind(PluginRespirator::class.java).toProvider(Provider { pluginRespirator }) + pluginRespirator.node!!.let { node -> bind(Node::class.java).toProvider(Provider { node }) } + bind(HighLevelSimpleClient::class.java).toProvider(Provider { pluginRespirator.hlSimpleClient!! }) + bind(ToadletContainer::class.java).toProvider(Provider { pluginRespirator.toadletContainer }) + bind(PageMaker::class.java).toProvider(Provider { pluginRespirator.pageMaker }) } - @Provides @Singleton + @Provides + @Singleton fun getSessionManager() = pluginRespirator.getSessionManager("Sone")!! } diff --git a/src/main/kotlin/net/pterodactylus/sone/main/SoneModuleCreator.kt b/src/main/kotlin/net/pterodactylus/sone/main/SoneModuleCreator.kt new file mode 100644 index 0000000..58c8d9e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/main/SoneModuleCreator.kt @@ -0,0 +1,65 @@ +package net.pterodactylus.sone.main + +import com.google.common.base.* +import com.google.common.eventbus.* +import com.google.inject.* +import com.google.inject.matcher.* +import com.google.inject.name.Names.* +import com.google.inject.spi.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.database.memory.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.util.config.* +import net.pterodactylus.util.config.ConfigurationException +import net.pterodactylus.util.version.Version +import java.io.* + +class SoneModuleCreator { + + fun createModule(sonePlugin: SonePlugin) = object : AbstractModule() { + override fun configure() { + val sonePropertiesFile = File("sone.properties") + val firstStart = !sonePropertiesFile.exists() + var newConfig = false + val configuration = try { + Configuration(MapConfigurationBackend(sonePropertiesFile, false)) + } catch (ce: ConfigurationException) { + sonePropertiesFile.delete() + newConfig = true + Configuration(MapConfigurationBackend(sonePropertiesFile, true)) + } + val context = Context("Sone") + val loaders = configuration.getStringValue("Developer.LoadFromFilesystem") + .getValue(null) + ?.let { + configuration.getStringValue("Developer.FilesystemPath") + .getValue(null) + ?.let { DebugLoaders(it) } + } + val eventBus = EventBus() + + bind(Configuration::class.java).toInstance(configuration) + bind(EventBus::class.java).toInstance(eventBus) + bind(Boolean::class.java).annotatedWith(named("FirstStart")).toInstance(firstStart) + bind(Boolean::class.java).annotatedWith(named("NewConfig")).toInstance(newConfig) + bind(Context::class.java).toInstance(context) + bind(object : TypeLiteral>() {}).toInstance(Optional.of(context)) + bind(SonePlugin::class.java).toInstance(sonePlugin) + bind(Version::class.java).toInstance(sonePlugin.version.parseVersion()) + bind(PluginVersion::class.java).toInstance(PluginVersion(sonePlugin.version)) + bind(PluginYear::class.java).toInstance(PluginYear(sonePlugin.year)) + bind(PluginHomepage::class.java).toInstance(PluginHomepage(sonePlugin.homepage)) + bind(Database::class.java).to(MemoryDatabase::class.java).`in`(Singleton::class.java) + loaders?.let { bind(Loaders::class.java).toInstance(it) } + + bindListener(Matchers.any(), object : TypeListener { + override fun hear(typeLiteral: TypeLiteral, typeEncounter: TypeEncounter) { + typeEncounter.register(InjectionListener { injectee -> eventBus.register(injectee) }) + } + }) + } + } + +} + +private fun String.parseVersion(): Version = Version.parse(this) diff --git a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt index 4536c04..200bd83 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt @@ -1,22 +1,18 @@ package net.pterodactylus.sone.template -import net.pterodactylus.sone.core.LinkedElement -import net.pterodactylus.sone.utils.asTemplate -import net.pterodactylus.util.template.Filter -import net.pterodactylus.util.template.TemplateContext -import net.pterodactylus.util.template.TemplateContextFactory -import java.io.StringWriter -import javax.inject.Inject +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.template.* +import java.io.* /** * Renders all kinds of [LinkedElement]s. */ -class LinkedElementRenderFilter @Inject constructor(private val templateContextFactory: TemplateContextFactory): Filter { +class LinkedElementRenderFilter : Filter { - companion object { - private val loadedImageTemplate = """<%include linked/image.html>""".asTemplate() - private val loadedHtmlPageTemplate = """<%include linked/html-page.html>""".asTemplate() - private val notLoadedImageTemplate = """<%include linked/notLoaded.html>""".asTemplate() + private val templateContextFactory = TemplateContextFactory().apply { + addFilter("html", HtmlFilter()) + addProvider(ClassPathTemplateProvider(LinkedElementRenderFilter::class.java, "/templates/")) } override fun format(templateContext: TemplateContext?, data: Any?, parameters: Map?) = @@ -51,3 +47,7 @@ class LinkedElementRenderFilter @Inject constructor(private val templateContextF }.toString() } + +private val loadedImageTemplate = """<%include linked/image.html>""".asTemplate() +private val loadedHtmlPageTemplate = """<%include linked/html-page.html>""".asTemplate() +private val notLoadedImageTemplate = """<%include linked/notLoaded.html>""".asTemplate() diff --git a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementsFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementsFilter.kt index c9414ea..0ed8df2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementsFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementsFilter.kt @@ -27,9 +27,9 @@ class LinkedElementsFilter(private val elementLoader: ElementLoader) : Filter { ?.filterIsInstance() ?.map { elementLoader.loadElement(it.link) } ?.filter { !it.failed } - ?: listOf() + ?: listOf() } else { - listOf() + listOf() } private fun showLinkedImages(currentSone: Sone?, sone: Sone?): Boolean { diff --git a/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt index 25df239..00015bb 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt @@ -1,33 +1,20 @@ package net.pterodactylus.sone.template -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.text.FreemailPart -import net.pterodactylus.sone.text.FreenetLinkPart -import net.pterodactylus.sone.text.LinkPart +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.text.* import net.pterodactylus.sone.text.Part -import net.pterodactylus.sone.text.PlainTextPart -import net.pterodactylus.sone.text.PostPart -import net.pterodactylus.sone.text.SonePart -import net.pterodactylus.sone.text.SoneTextParser -import net.pterodactylus.sone.text.SoneTextParserContext -import net.pterodactylus.sone.utils.asTemplate -import net.pterodactylus.util.template.Filter -import net.pterodactylus.util.template.TemplateContext -import net.pterodactylus.util.template.TemplateContextFactory -import java.io.StringWriter -import java.io.Writer -import java.net.URLEncoder +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.template.* +import java.io.* +import java.net.* /** * Renders a number of pre-parsed [Part] into a [String]. - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) */ -class RenderFilter(private val core: Core, private val templateContextFactory: TemplateContextFactory) : Filter { +class RenderFilter(private val soneProvider: SoneProvider, private val soneTextParser: SoneTextParser, htmlFilter: HtmlFilter) : Filter { - companion object { - private val plainTextTemplate = "<%text|html>".asTemplate() - private val linkTemplate = "\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html>".asTemplate() + private val templateContextFactory = TemplateContextFactory().apply { + addFilter("html", htmlFilter) } override fun format(templateContext: TemplateContext?, data: Any?, parameters: MutableMap?): Any? { @@ -79,9 +66,8 @@ class RenderFilter(private val core: Core, private val templateContextFactory: T } private fun render(writer: Writer, postPart: PostPart) { - val parser = SoneTextParser(core, core) val parserContext = SoneTextParserContext(postPart.post.sone) - val parts = parser.parse(postPart.post.text, parserContext) + val parts = soneTextParser.parse(postPart.post.text, parserContext) val excerpt = StringBuilder() for (part in parts) { excerpt.append(part.text) @@ -100,7 +86,7 @@ class RenderFilter(private val core: Core, private val templateContextFactory: T } private fun render(writer: Writer, freemailPart: FreemailPart) { - val sone = core.getSone(freemailPart.identityId) + val sone = soneProvider.getSone(freemailPart.identityId) val soneName = sone?.let(SoneAccessor::getNiceName) ?: freemailPart.identityId renderLink(writer, "/Freemail/NewMessage?to=${freemailPart.identityId}", @@ -119,3 +105,6 @@ class RenderFilter(private val core: Core, private val templateContextFactory: T } } + +private val plainTextTemplate = "<%text|html>".asTemplate() +private val linkTemplate = "\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html>".asTemplate() diff --git a/src/main/kotlin/net/pterodactylus/sone/text/PlainTextPart.kt b/src/main/kotlin/net/pterodactylus/sone/text/PlainTextPart.kt index 4a495b4..4137fe9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/text/PlainTextPart.kt +++ b/src/main/kotlin/net/pterodactylus/sone/text/PlainTextPart.kt @@ -2,7 +2,5 @@ package net.pterodactylus.sone.text /** * [Part] implementation that holds a single piece of text. - * - * @author [David Roden](mailto:d.roden@emetriq.com) */ data class PlainTextPart(override val text: String) : Part diff --git a/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt b/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt index 64125c1..554c19b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt +++ b/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt @@ -1,28 +1,20 @@ package net.pterodactylus.sone.text -import freenet.keys.FreenetURI -import freenet.support.Base64 -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.data.impl.IdOnlySone -import net.pterodactylus.sone.database.PostProvider -import net.pterodactylus.sone.database.SoneProvider -import net.pterodactylus.sone.text.LinkType.CHK -import net.pterodactylus.sone.text.LinkType.FREEMAIL -import net.pterodactylus.sone.text.LinkType.HTTP -import net.pterodactylus.sone.text.LinkType.HTTPS -import net.pterodactylus.sone.text.LinkType.KSK -import net.pterodactylus.sone.text.LinkType.POST -import net.pterodactylus.sone.text.LinkType.SONE -import net.pterodactylus.sone.text.LinkType.SSK +import freenet.keys.* +import freenet.support.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.impl.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.text.LinkType.* import net.pterodactylus.sone.text.LinkType.USK -import net.pterodactylus.sone.utils.let -import org.bitpedia.util.Base32 -import java.net.MalformedURLException +import org.bitpedia.util.* +import java.net.* +import javax.inject.* /** * [Parser] implementation that can recognize Freenet URIs. */ -class SoneTextParser(private val soneProvider: SoneProvider?, private val postProvider: PostProvider?) { +class SoneTextParser @Inject constructor(private val soneProvider: SoneProvider?, private val postProvider: PostProvider?) { fun parse(source: String, context: SoneTextParserContext?) = source.split("\n") @@ -50,27 +42,39 @@ class SoneTextParser(private val soneProvider: SoneProvider?, private val postPr } }.map { it.first }.toList() + private val NextLink.linkWithoutBacklink: String + get() { + val backlink = link.indexOf("/../") + val query = link.indexOf("?") + return if ((backlink > -1) && ((query == -1) || (query > -1) && (backlink < query))) + link.substring(0, backlink) + else + link + } + private fun NextLink.toPart(context: SoneTextParserContext?) = when (linkType) { KSK, CHK -> try { - FreenetURI(link).let { freenetUri -> + FreenetURI(linkWithoutBacklink).let { freenetUri -> FreenetLinkPart( - link, - if (freenetUri.isKSK) { - freenetUri.guessableKey - } else { - freenetUri.metaString ?: freenetUri.docName ?: link.substring(0, 9) - }, - link.split('?').first() + linkWithoutBacklink, + freenetUri.allMetaStrings?.lastOrNull { it != "" } ?: freenetUri.docName ?: linkWithoutBacklink.substring(0, 9), + linkWithoutBacklink.split('?').first() ) } } catch (e: MalformedURLException) { - PlainTextPart(link) + PlainTextPart(linkWithoutBacklink) } SSK, USK -> try { - FreenetLinkPart(link, FreenetURI(link).docName, trusted = context?.routingKey?.contentEquals(FreenetURI(link).routingKey) == true) + FreenetURI(linkWithoutBacklink).let { uri -> + uri.allMetaStrings + ?.takeIf { (it.size > 1) || ((it.size == 1) && (it.single() != "")) } + ?.lastOrNull() + ?: uri.docName + ?: "${uri.keyType}@${uri.routingKey.freenetBase64}" + }.let { FreenetLinkPart(linkWithoutBacklink.removeSuffix("/"), it, trusted = context?.routingKey?.contentEquals(FreenetURI(linkWithoutBacklink).routingKey) == true) } } catch (e: MalformedURLException) { - PlainTextPart(link) + PlainTextPart(linkWithoutBacklink) } SONE -> link.substring(7).let { SonePart(soneProvider?.getSone(it) ?: IdOnlySone(it)) } POST -> postProvider?.getPost(link.substring(7))?.let { PostPart(it) } ?: PlainTextPart(link) @@ -195,3 +199,5 @@ private fun isPunctuation(char: Char) = char in punctuationChars private val whitespace = Regex("[\\u000a\u0020\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u200c\u200d\u202f\u205f\u2060\u2800\u3000]") private data class NextLink(val position: Int, val linkType: LinkType, val link: String, val remainder: String) + +private val ByteArray.freenetBase64 get() = Base64.encode(this)!! diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Objects.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Objects.kt index 36e530c..6d1d413 100644 --- a/src/main/kotlin/net/pterodactylus/sone/utils/Objects.kt +++ b/src/main/kotlin/net/pterodactylus/sone/utils/Objects.kt @@ -1,3 +1,7 @@ package net.pterodactylus.sone.utils -fun T?.asList() = this?.let(::listOf) ?: emptyList() +fun T?.asList() = this?.let(::listOf) ?: emptyList() +val Any?.unit get() = Unit + +fun T?.throwOnNullIf(throwCondition: Boolean, exception: () -> Throwable) = + if (this == null && throwCondition) throw exception() else this diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Pagination.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Pagination.kt index 6c436e2..5d48d61 100644 --- a/src/main/kotlin/net/pterodactylus/sone/utils/Pagination.kt +++ b/src/main/kotlin/net/pterodactylus/sone/utils/Pagination.kt @@ -39,6 +39,9 @@ class Pagination(private val originalItems: List, pageSize: Int): Iter override fun iterator() = items.iterator() + fun turnTo(page: Int) = apply { this.page = page } + } -fun Iterable.paginate(pageSize: Int) = Pagination(toList(), pageSize) +fun Iterable.paginate(pageSize: Int) = Pagination(toList(), pageSize) +fun Sequence.paginate(pageSize: Int) = Pagination(toList(), pageSize) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/PageToadletRegistry.kt b/src/main/kotlin/net/pterodactylus/sone/web/PageToadletRegistry.kt new file mode 100644 index 0000000..97e6cfe --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/PageToadletRegistry.kt @@ -0,0 +1,58 @@ +package net.pterodactylus.sone.web + +import freenet.clients.http.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.* +import java.util.concurrent.atomic.* +import javax.inject.* + +private const val soneMenu = "Navigation.Menu.Sone" +private const val soneMenuName = "$soneMenu.Name" + +class PageToadletRegistry @Inject constructor( + private val pageMaker: PageMaker, + private val toadletContainer: ToadletContainer, + private val sonePlugin: SonePlugin, + private val pageToadletFactory: PageToadletFactory +) { + + private val pages = mutableListOf>() + private val registeredToadlets = mutableListOf() + private val registered = AtomicBoolean(false) + + fun addPage(page: Page) { + if (registered.get()) throw IllegalStateException() + pages += page + } + + fun registerToadlets() { + registered.set(true) + pageMaker.addNavigationCategory("/Sone/index.html", soneMenuName, "$soneMenu.Tooltip", sonePlugin) + addPages() + } + + private fun addPages() = + pages + .map { pageToadletFactory.createPageToadlet(it) } + .onEach(registeredToadlets::plusAssign) + .forEach { pageToadlet -> + if (pageToadlet.menuName == null) { + registerToadletWithoutMenuname(pageToadlet) + } else { + registerToadletWithMenuname(pageToadlet) + } + } + + private fun registerToadletWithoutMenuname(pageToadlet: PageToadlet) = + toadletContainer.register(pageToadlet, null, pageToadlet.path(), true, false) + + private fun registerToadletWithMenuname(pageToadlet: PageToadlet) = + toadletContainer.register(pageToadlet, soneMenuName, pageToadlet.path(), true, "$soneMenu.Item.${pageToadlet.menuName}.Name", "$soneMenu.Item.${pageToadlet.menuName}.Tooltip", false, pageToadlet) + + fun unregisterToadlets() { + pageMaker.removeNavigationCategory(soneMenuName) + registeredToadlets.forEach(toadletContainer::unregister) + } + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/WebInterfaceModule.kt b/src/main/kotlin/net/pterodactylus/sone/web/WebInterfaceModule.kt new file mode 100644 index 0000000..dd5e9f6 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/WebInterfaceModule.kt @@ -0,0 +1,128 @@ +package net.pterodactylus.sone.web + +import com.google.inject.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.freenet.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.template.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.util.template.* +import javax.inject.* +import javax.inject.Singleton + +class WebInterfaceModule : AbstractModule() { + + @Provides + @Singleton + fun getTemplateContextFactory( + soneAccessor: SoneAccessor, + postAccessor: PostAccessor, + replyAccessor: ReplyAccessor, + identityAccessor: IdentityAccessor, + profileAccessor: ProfileAccessor, + l10nFilter: L10nFilter, + parserFilter: ParserFilter, + renderFilter: RenderFilter, + linkedElementsFilter: LinkedElementsFilter, + unknownDateFilter: UnknownDateFilter, + imageLinkFilter: ImageLinkFilter, + loaders: Loaders + ) = + TemplateContextFactory().apply { + addAccessor(Any::class.java, ReflectionAccessor()) + addAccessor(Collection::class.java, CollectionAccessor()) + addAccessor(Sone::class.java, soneAccessor) + addAccessor(Post::class.java, postAccessor) + addAccessor(Reply::class.java, replyAccessor) + addAccessor(Album::class.java, AlbumAccessor()) + addAccessor(Image::class.java, ImageAccessor()) + addAccessor(Identity::class.java, identityAccessor) + addAccessor(Trust::class.java, TrustAccessor()) + addAccessor(HTTPRequest::class.java, HttpRequestAccessor()) + addAccessor(Profile::class.java, profileAccessor) + + addFilter("date", DateFilter()) + addFilter("html", HtmlFilter()) + addFilter("replace", ReplaceFilter()) + addFilter("store", StoreFilter()) + addFilter("l10n", l10nFilter) + addFilter("substring", SubstringFilter()) + addFilter("xml", XmlFilter()) + addFilter("change", RequestChangeFilter()) + addFilter("match", MatchFilter()) + addFilter("css", CssClassNameFilter()) + addFilter("js", JavascriptFilter()) + addFilter("parse", parserFilter) + addFilter("shorten", ShortenFilter()) + addFilter("render", renderFilter) + addFilter("linked-elements", linkedElementsFilter) + addFilter("render-linked-element", LinkedElementRenderFilter()) + addFilter("reparse", ReparseFilter()) + addFilter("unknown", unknownDateFilter) + addFilter("format", FormatFilter()) + addFilter("sort", CollectionSortFilter()) + addFilter("image-link", imageLinkFilter) + addFilter("replyGroup", ReplyGroupFilter()) + addFilter("in", ContainsFilter()) + addFilter("unique", UniqueElementFilter()) + addFilter("mod", ModFilter()) + addFilter("paginate", PaginationFilter()) + + addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER) + addProvider(loaders.templateProvider) + } + + @Provides + fun getSoneAccessor(core: Core, timeTextConverter: TimeTextConverter) = + SoneAccessor(core, timeTextConverter) + + @Provides + fun getPostAccessor(core: Core) = + PostAccessor(core) + + @Provides + fun getReplyAccessor(core: Core) = + ReplyAccessor(core) + + @Provides + fun getIdentityAccessor(core: Core) = + IdentityAccessor(core) + + @Provides + fun getProfileAccessor(core: Core) = + ProfileAccessor(core) + + @Provides + fun getL10nFilter(l10n: BaseL10n) = + L10nFilter(l10n) + + @Provides + fun getParserFilter(core: Core, soneTextParser: SoneTextParser) = + ParserFilter(core, soneTextParser) + + @Provides + fun getRenderFilter(soneProvider: SoneProvider, soneTextParser: SoneTextParser, htmlFilter: HtmlFilter) = + RenderFilter(soneProvider, soneTextParser, htmlFilter) + + @Provides + fun getLinkedElementsFilter(elementLoader: ElementLoader) = + LinkedElementsFilter(elementLoader) + + @Provides + fun getUnknownDateFilter(l10n: BaseL10n) = + UnknownDateFilter(l10n, "View.Sone.Text.UnknownDate") + + @Provides + fun getImageLinkFilter(core: Core) = + ImageLinkFilter(core) + + @Provides + @Named("toadletPathPrefix") + fun getPathPrefix(): String = "/Sone/" + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt index 35ac0e2..e9a1a50 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt @@ -3,12 +3,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.utils.emptyToNull import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user bookmark a post. */ -class BookmarkAjaxPage(webInterface: WebInterface) : JsonPage("bookmark.ajax", webInterface) { +@ToadletPath("bookmark.ajax") +class BookmarkAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt index 868e990..79e66ad 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt @@ -1,19 +1,17 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.asOptional -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.headers -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * AJAX handler that creates a new post. */ -class CreatePostAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("createPost.ajax", webInterface) { +@ToadletPath("createPost.ajax") +class CreatePostAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["text"].emptyToNull diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt index f817e28..df86dc0 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt @@ -1,18 +1,17 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.headers -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * This AJAX page create a reply. */ -class CreateReplyAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("createReply.ajax", webInterface) { +@ToadletPath("createReply.ajax") +class CreateReplyAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest): JsonReturnObject = request.parameters["post"].emptyToNull diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt index 6dcf032..3dca438 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt @@ -1,16 +1,16 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.ifTrue -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * This AJAX page deletes a post. */ -class DeletePostAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("deletePost.ajax", webInterface) { +@ToadletPath("deletePost.ajax") +class DeletePostAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["post"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.kt index 05f53da..6daa4da 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.kt @@ -3,12 +3,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user delete a profile field. */ -class DeleteProfileFieldAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("deleteProfileField.ajax", webInterface) { +@ToadletPath("deleteProfileField.ajax") +class DeleteProfileFieldAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = currentSone.profile.let { profile -> diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt index d01c077..b558356 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt @@ -1,16 +1,16 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.ifTrue -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * This AJAX page deletes a reply. */ -class DeleteReplyAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("deleteReply.ajax", webInterface) { +@ToadletPath("deleteReply.ajax") +class DeleteReplyAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["reply"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.kt index 539d57b..06fe51b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.kt @@ -4,12 +4,14 @@ import net.pterodactylus.sone.utils.ifTrue import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user dismiss a notification. */ -class DismissNotificationAjaxPage(webInterface: WebInterface) : JsonPage("dismissNotification.ajax", webInterface) { +@ToadletPath("dismissNotification.ajax") +class DismissNotificationAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt index 4eadfde..cbeed6e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt @@ -1,18 +1,19 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * AJAX page that lets the user distrust a Sone. * * @see Core.distrustSone(Sone, Sone) */ -class DistrustAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("distrustSone.ajax", webInterface) { +@ToadletPath("distrustSone.ajax") +class DistrustAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.kt index 321ee7d..39442f0 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.kt @@ -5,12 +5,14 @@ import net.pterodactylus.sone.utils.headers import net.pterodactylus.sone.utils.ifTrue import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * Page that stores a user’s album modifications. */ -class EditAlbumAjaxPage(webInterface: WebInterface) : JsonPage("editAlbum.ajax", webInterface) { +@ToadletPath("editAlbum.ajax") +class EditAlbumAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override fun createJsonObject(request: FreenetRequest) = request.parameters["album"]!! diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.kt index dbeb2d2..7012cdc 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.kt @@ -8,16 +8,18 @@ import net.pterodactylus.sone.utils.headers import net.pterodactylus.sone.utils.ifTrue import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import net.pterodactylus.util.template.TemplateContext +import javax.inject.Inject /** * Page that stores a user’s image modifications. */ -class EditImageAjaxPage(webInterface: WebInterface, +@ToadletPath("editImage.ajax") +class EditImageAjaxPage @Inject constructor(webInterface: WebInterface, private val parserFilter: ParserFilter, private val shortenFilter: ShortenFilter, - private val renderFilter: RenderFilter) : JsonPage("editImage.ajax", webInterface) { + private val renderFilter: RenderFilter) : JsonPage(webInterface) { override fun createJsonObject(request: FreenetRequest) = request.parameters["image"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.kt index e48c92d..9d5346c 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.kt @@ -4,12 +4,14 @@ import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.ifFalse import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user rename a profile field. */ -class EditProfileFieldAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("editProfileField.ajax", webInterface) { +@ToadletPath("editProfileField.ajax") +class EditProfileFieldAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = currentSone.profile.let { profile -> diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt index 0c37ac0..eea5120 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt @@ -1,16 +1,16 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.also -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets a Sone follow another Sone. */ -class FollowSoneAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("followSone.ajax", webInterface) { +@ToadletPath("followSone.ajax") +class FollowSoneAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt index 77e2c87..1175b2b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt @@ -4,16 +4,17 @@ import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.template.SoneAccessor import net.pterodactylus.sone.utils.jsonArray import net.pterodactylus.sone.utils.jsonObject -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that retrieves the number of “likes” a [net.pterodactylus.sone.data.Post] * or [net.pterodactylus.sone.data.PostReply] has. */ -class GetLikesAjaxPage(webInterface: WebInterface) : JsonPage("getLikes.ajax", webInterface) { +@ToadletPath("getLikes.ajax") +class GetLikesAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val needsFormPassword = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt index 809abdc..115370a 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt @@ -8,13 +8,15 @@ import net.pterodactylus.sone.template.LinkedElementRenderFilter import net.pterodactylus.sone.utils.jsonArray import net.pterodactylus.sone.utils.jsonObject import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * Renders linked elements after they have been loaded. */ -class GetLinkedElementAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val linkedElementRenderFilter: LinkedElementRenderFilter): - JsonPage("getLinkedElement.ajax", webInterface) { +@ToadletPath("getLinkedElement.ajax") +class GetLinkedElementAjaxPage @Inject constructor(webInterface: WebInterface, private val elementLoader: ElementLoader, private val linkedElementRenderFilter: LinkedElementRenderFilter): + JsonPage(webInterface) { override val needsFormPassword = false override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.kt index 19cdd24..db6e5c5 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.kt @@ -6,15 +6,17 @@ import net.pterodactylus.sone.main.SonePlugin import net.pterodactylus.sone.utils.jsonArray import net.pterodactylus.sone.utils.jsonObject import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import net.pterodactylus.util.notify.Notification import net.pterodactylus.util.notify.TemplateNotification import java.io.StringWriter +import javax.inject.Inject /** * AJAX handler to return all current notifications. */ -class GetNotificationsAjaxPage(webInterface: WebInterface) : JsonPage("getNotifications.ajax", webInterface) { +@ToadletPath("getNotifications.ajax") +class GetNotificationsAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val needsFormPassword = false override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt index d91fe90..1aedd49 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt @@ -3,17 +3,18 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.jsonObject -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.utils.render import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import net.pterodactylus.util.template.Template +import javax.inject.Inject /** * This AJAX handler retrieves information and rendered representation of a [Post]. */ -class GetPostAjaxPage(webInterface: WebInterface, private val postTemplate: Template) : LoggedInJsonPage("getPost.ajax", webInterface) { +@ToadletPath("getPost.ajax") +class GetPostAjaxPage @Inject constructor(webInterface: WebInterface, private val postTemplate: Template) : LoggedInJsonPage(webInterface) { override val needsFormPassword = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt index b02b85b..ec5a5ac 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt @@ -3,17 +3,18 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.jsonObject -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.utils.render import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import net.pterodactylus.util.template.Template +import javax.inject.Inject /** * This AJAX page returns the details of a reply. */ -class GetReplyAjaxPage(webInterface: WebInterface, private val template: Template) : LoggedInJsonPage("getReply.ajax", webInterface) { +@ToadletPath("getReply.ajax") +class GetReplyAjaxPage @Inject constructor(webInterface: WebInterface, private val template: Template) : LoggedInJsonPage(webInterface) { override val needsFormPassword = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt index 7646704..75f3c3c 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt @@ -12,19 +12,23 @@ import net.pterodactylus.sone.freenet.L10nFilter import net.pterodactylus.sone.template.SoneAccessor import net.pterodactylus.sone.text.TimeTextConverter import net.pterodactylus.sone.utils.jsonObject -import net.pterodactylus.sone.utils.mapPresent import net.pterodactylus.sone.utils.toArray import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import java.text.SimpleDateFormat import java.util.TimeZone +import javax.inject.Inject /** * The “get status” AJAX handler returns all information that is necessary to * update the web interface in real-time. */ -class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter, timeZone: TimeZone = TimeZone.getDefault()): - JsonPage("getStatus.ajax", webInterface) { +@ToadletPath("getStatus.ajax") +class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter, timeZone: TimeZone): + JsonPage(webInterface) { + + @Inject constructor(webInterface: WebInterface, elementLoader: ElementLoader, timeTextConverter: TimeTextConverter, l10nFilter: L10nFilter): + this(webInterface, elementLoader, timeTextConverter, l10nFilter, TimeZone.getDefault()) private val dateFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss").apply { this.timeZone = timeZone diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt index cb3b86d..ef4a0db 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt @@ -5,17 +5,19 @@ import net.pterodactylus.sone.text.TimeTextConverter import net.pterodactylus.sone.utils.jsonObject import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import java.text.SimpleDateFormat import java.util.TimeZone +import javax.inject.Inject /** * Ajax page that returns a formatted, relative timestamp for replies or posts. */ -class GetTimesAjaxPage(webInterface: WebInterface, +@ToadletPath("getTimes.ajax") +class GetTimesAjaxPage @Inject constructor(webInterface: WebInterface, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter, - timeZone: TimeZone) : JsonPage("getTimes.ajax", webInterface) { + timeZone: TimeZone) : JsonPage(webInterface) { private val dateTimeFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss").apply { this.timeZone = timeZone diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPage.kt index d260655..41188ea 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPage.kt @@ -2,12 +2,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * Returns the translation for a given key as JSON object. */ -class GetTranslationAjaxPage(webInterface: WebInterface) : JsonPage("getTranslation.ajax", webInterface) { +@ToadletPath("getTranslation.ajax") +class GetTranslationAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val needsFormPassword = false override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/JsonPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/JsonPage.kt index 2da5edc..99c0828 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/JsonPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/JsonPage.kt @@ -5,7 +5,7 @@ import freenet.clients.http.ToadletContext import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.SessionProvider import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* import net.pterodactylus.util.web.Page import net.pterodactylus.util.web.Response import java.io.ByteArrayOutputStream @@ -15,13 +15,13 @@ import java.io.PrintStream * A JSON page is a specialized [Page] that will always return a JSON * object to the browser, e.g. for use with AJAX or other scripting frameworks. */ -abstract class JsonPage(private val path: String, protected val webInterface: WebInterface) : Page { +abstract class JsonPage(protected val webInterface: WebInterface) : Page { private val objectMapper = ObjectMapper() private val sessionProvider: SessionProvider = webInterface protected val core = webInterface.core - override fun getPath() = path + override fun getPath() = toadletPath override fun isPrefixPage() = false open val needsFormPassword = true @@ -35,7 +35,7 @@ abstract class JsonPage(private val path: String, protected val webInterface: We sessionProvider.getCurrentSone(toadletContext, createSession) override fun handleRequest(request: FreenetRequest, response: Response): Response { - if (core.preferences.isRequireFullAccess && !request.toadletContext.isAllowedFullAccess) { + if (core.preferences.requireFullAccess && !request.toadletContext.isAllowedFullAccess) { return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(createErrorJsonObject("auth-required").asJsonString()) } if (needsFormPassword && request.parameters["formPassword"] != webInterface.formPassword) { diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt index 718e6e7..b2993f4 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt @@ -1,15 +1,16 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user like a [net.pterodactylus.sone.data.Post]. */ -class LikeAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("like.ajax", webInterface) { +@ToadletPath("like.ajax") +class LikeAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = when (request.parameters["type"]) { diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.kt index 8605fe6..c177041 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.kt @@ -2,12 +2,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * Lets the user [lock][net.pterodactylus.sone.core.Core.lockSone] a [Sone][net.pterodactylus.sone.data.Sone]. */ -class LockSoneAjaxPage(webInterface: WebInterface) : JsonPage("lockSone.ajax", webInterface) { +@ToadletPath("lockSone.ajax") +class LockSoneAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPage.kt index 388c289..d1afaec 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPage.kt @@ -7,7 +7,7 @@ import net.pterodactylus.sone.web.page.FreenetRequest /** * Base JSON page for all pages that require the user to be logged in. */ -open class LoggedInJsonPage(path: String, webInterface: WebInterface) : JsonPage(path, webInterface) { +open class LoggedInJsonPage(webInterface: WebInterface) : JsonPage(webInterface) { final override val requiresLogin = true diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt index 0451eaa..808d2fa 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt @@ -2,13 +2,15 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user mark a number of [net.pterodactylus.sone.data.Sone]s, * [net.pterodactylus.sone.data.Post]s, or [net.pterodactylus.sone.data.Reply]s as known. */ -class MarkAsKnownAjaxPage(webInterface: WebInterface) : JsonPage("markAsKnown.ajax", webInterface) { +@ToadletPath("markAsKnown.ajax") +class MarkAsKnownAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.kt index 1c050bf..0b2c5ab 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.kt @@ -5,7 +5,8 @@ import net.pterodactylus.sone.data.Profile.Field import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user move a profile field up or down. @@ -13,7 +14,8 @@ import net.pterodactylus.sone.web.page.FreenetRequest * @see net.pterodactylus.sone.data.Profile#moveFieldUp(Field) * @see net.pterodactylus.sone.data.Profile#moveFieldDown(Field) */ -class MoveProfileFieldAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("moveProfileField.ajax", webInterface) { +@ToadletPath("moveProfileField.ajax") +class MoveProfileFieldAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = currentSone.profile.let { profile -> diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt index 1dfb058..9f0de87 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt @@ -1,17 +1,18 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import javax.inject.* /** * AJAX page that lets the user trust a Sone. * * @see net.pterodactylus.sone.core.Core.trustSone */ -class TrustAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("trustSone.ajax", webInterface) { +@ToadletPath("trustSone.ajax") +class TrustAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.kt index f8331fe..bc61b21 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.kt @@ -1,15 +1,15 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.utils.also -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user unbookmark a post. */ -class UnbookmarkAjaxPage(webInterface: WebInterface) : JsonPage("unbookmark.ajax", webInterface) { +@ToadletPath("unbookmark.ajax") +class UnbookmarkAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt index 83b474c..d8b8290 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt @@ -3,12 +3,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets a Sone unfollow another Sone. */ -class UnfollowSoneAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("unfollowSone.ajax", webInterface) { +@ToadletPath("unfollowSone.ajax") +class UnfollowSoneAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.kt index b30829a..a8da594 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.kt @@ -4,12 +4,14 @@ import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.emptyToNull import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user unlike a [net.pterodactylus.sone.data.Post]. */ -class UnlikeAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("unlike.ajax", webInterface) { +@ToadletPath("unlike.ajax") +class UnlikeAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = when (request.parameters["type"]) { "post" -> request.processEntity("post", currentSone::removeLikedPostId) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.kt index 7d77c05..130d102 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.kt @@ -2,12 +2,14 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * Lets the user [unlock][net.pterodactylus.sone.core.Core.unlockSone] a [Sone][net.pterodactylus.sone.data.Sone]. */ -class UnlockSoneAjaxPage(webInterface: WebInterface) : JsonPage("unlockSone.ajax", webInterface) { +@ToadletPath("unlockSone.ajax") +class UnlockSoneAjaxPage @Inject constructor(webInterface: WebInterface) : JsonPage(webInterface) { override val requiresLogin = false diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.kt index c6274a2..e4b5edb 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.kt @@ -1,16 +1,16 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.also -import net.pterodactylus.sone.utils.let import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.web.page.* +import javax.inject.Inject /** * AJAX page that lets the user [untrust][net.pterodactylus.sone.core.Core.untrustSone] a [Sone]. */ -class UntrustAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("untrustSone.ajax", webInterface) { +@ToadletPath("untrustSone.ajax") +class UntrustAjaxPage @Inject constructor(webInterface: WebInterface) : LoggedInJsonPage(webInterface) { override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/Annotations.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/Annotations.kt new file mode 100644 index 0000000..8287130 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/Annotations.kt @@ -0,0 +1,15 @@ +package net.pterodactylus.sone.web.page + +import net.pterodactylus.util.web.* + +annotation class MenuName(val value: String) + +val Page<*>.menuName get() = javaClass.getAnnotation(MenuName::class.java)?.value + +annotation class TemplatePath(val value: String) + +val Page<*>.templatePath get() = javaClass.getAnnotation(TemplatePath::class.java)?.value + +annotation class ToadletPath(val value: String) + +val Page<*>.toadletPath get() = javaClass.getAnnotation(ToadletPath::class.java)?.value diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetPage.kt new file mode 100644 index 0000000..2af0eca --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetPage.kt @@ -0,0 +1,27 @@ +/* + * Sone - FreenetPage.kt - Copyright © 2011–2019 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 . + */ + +package net.pterodactylus.sone.web.page + +import net.pterodactylus.util.web.* +import java.net.* + +interface FreenetPage : Page { + + fun isLinkExcepted(link: URI): Boolean + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetRequest.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetRequest.kt new file mode 100644 index 0000000..54c8f7f --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetRequest.kt @@ -0,0 +1,42 @@ +/* + * Sone - FreenetRequest.kt - Copyright © 2011–2019 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 . + */ + +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import freenet.clients.http.SessionManager.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.util.web.* +import java.net.* +import java.util.UUID.* + +open class FreenetRequest(uri: URI, method: Method, + val httpRequest: HTTPRequest, + val toadletContext: ToadletContext, + val l10n: BaseL10n, + val sessionManager: SessionManager +) : Request(uri, method) { + + val session: Session + get() = + sessionManager.useSession(toadletContext) + ?: sessionManager.createSession(randomUUID().toString(), toadletContext) + + val existingSession: Session? get() = sessionManager.useSession(toadletContext) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePage.kt new file mode 100644 index 0000000..2dcef51 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePage.kt @@ -0,0 +1,107 @@ +/* + * Sone - FreenetTemplatePage.kt - Copyright © 2010–2019 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 . + */ + +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.web.* +import java.lang.String.* +import java.net.* +import java.util.logging.* +import java.util.logging.Logger.* + +/** + * Base class for all [Page]s that are rendered with [Template]s and + * fit into Freenet’s web interface. + */ +open class FreenetTemplatePage( + private val templateRenderer: TemplateRenderer, + loaders: Loaders, + private val invalidFormPasswordRedirectTarget: String +) : FreenetPage, LinkEnabledCallback { + + private val pageMakerInteractionFactory: PageMakerInteractionFactory = DefaultPageMakerInteractionFactory() + open val styleSheets: Collection = emptySet() + open val shortcutIcon: String? get() = null + open val isFullAccessOnly get() = false + + override fun getPath() = toadletPath + + open fun getPageTitle(request: FreenetRequest) = "" + + override fun isPrefixPage() = false + + open fun getRedirectTarget(request: FreenetRequest): String? = null + + open fun getAdditionalLinkNodes(request: FreenetRequest): List> = emptyList() + + override fun isLinkExcepted(link: URI) = false + + override fun isEnabled(toadletContext: ToadletContext) = !isFullAccessOnly + + private val template = templatePath?.let(loaders::loadTemplate) ?: Template() + + override fun handleRequest(request: FreenetRequest, response: Response): Response { + getRedirectTarget(request)?.let { redirectTarget -> return RedirectResponse(redirectTarget) } + + if (isFullAccessOnly && !request.toadletContext.isAllowedFullAccess) { + return response.setStatusCode(401).setStatusText("Not authorized").setContentType("text/html") + } + val toadletContext = request.toadletContext + if (request.method == Method.POST) { + /* require form password. */ + val formPassword = request.httpRequest.getPartAsStringFailsafe("formPassword", 32) + if (formPassword != toadletContext.container.formPassword) { + return RedirectResponse(invalidFormPasswordRedirectTarget) + } + } + + val pageMakerInteraction = pageMakerInteractionFactory.createPageMaker(toadletContext, getPageTitle(request)) + styleSheets.forEach(pageMakerInteraction::addStyleSheet) + getAdditionalLinkNodes(request).forEach(pageMakerInteraction::addLinkNode) + shortcutIcon?.let(pageMakerInteraction::addShortcutIcon) + + val output = try { + val start = System.nanoTime() + templateRenderer.render(template) { templateContext -> + processTemplate(request, templateContext) + }.also { + val finish = System.nanoTime() + logger.log(Level.FINEST, format("Template was rendered in %.2fms.", (finish - start) / 1000000.0)) + } + } catch (re1: RedirectException) { + return RedirectResponse(re1.target ?: "") + } + + pageMakerInteraction.setContent(output) + + return response.setStatusCode(200).setStatusText("OK").setContentType("text/html").write(pageMakerInteraction.renderPage()) + } + + open fun processTemplate(request: FreenetRequest, templateContext: TemplateContext) { + /* do nothing. */ + } + + class RedirectException(val target: String?) : Exception() { + override fun toString(): String = format("RedirectException{target='%s'}", target) + } + +} + +private val logger: Logger = getLogger(FreenetTemplatePage::class.java.name) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteraction.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteraction.kt new file mode 100644 index 0000000..8d6884c --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteraction.kt @@ -0,0 +1,31 @@ +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* + +class PageMakerInteraction(toadletContext: ToadletContext, pageTitle: String) { + + private val pageMaker: PageMaker = toadletContext.pageMaker + private val pageNode: PageNode = pageMaker.getPageNode(pageTitle, toadletContext) + + fun addStyleSheet(styleSheet: String) { + pageNode.addCustomStyleSheet(styleSheet) + } + + fun addLinkNode(linkAttributes: Map) { + pageNode.headNode.addChild("link").let { + linkAttributes.forEach(it::addAttribute) + } + } + + fun addShortcutIcon(shortcutIcon: String) { + pageNode.addForwardLink("icon", shortcutIcon) + } + + fun setContent(content: String) { + pageNode.content.addChild("%", content) + } + + fun renderPage(): String = + pageNode.outer.generate() + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactory.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactory.kt new file mode 100644 index 0000000..e55e33f --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactory.kt @@ -0,0 +1,18 @@ +package net.pterodactylus.sone.web.page + +import com.google.inject.* +import freenet.clients.http.* + +@ImplementedBy(DefaultPageMakerInteractionFactory::class) +interface PageMakerInteractionFactory { + + fun createPageMaker(toadletContext: ToadletContext, pageTitle: String): PageMakerInteraction + +} + +class DefaultPageMakerInteractionFactory : PageMakerInteractionFactory { + + override fun createPageMaker(toadletContext: ToadletContext, pageTitle: String) = + PageMakerInteraction(toadletContext, pageTitle) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/PageToadletFactory.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/PageToadletFactory.kt new file mode 100644 index 0000000..3c84c09 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/PageToadletFactory.kt @@ -0,0 +1,35 @@ +/* + * Sone - PageToadletFactory.kt - Copyright © 2010–2019 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 . + */ + +package net.pterodactylus.sone.web.page + +import freenet.client.* +import freenet.clients.http.* +import net.pterodactylus.util.web.* +import javax.inject.* + +class PageToadletFactory @Inject constructor( + private val highLevelSimpleClient: HighLevelSimpleClient, + private val sessionManager: SessionManager, + @Named("toadletPathPrefix") private val pathPrefix: String +) { + + @JvmOverloads + fun createPageToadlet(page: Page, menuName: String? = null) = + PageToadlet(highLevelSimpleClient, sessionManager, menuName ?: page.menuName, page, pathPrefix) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/SoneRequest.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/SoneRequest.kt new file mode 100644 index 0000000..d3eed37 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/SoneRequest.kt @@ -0,0 +1,16 @@ +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.* +import java.net.* + +class SoneRequest(uri: URI, method: Method, httpRequest: HTTPRequest, toadletContext: ToadletContext, l10n: BaseL10n, sessionManager: SessionManager, + val core: Core, + val webInterface: WebInterface +) : FreenetRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager) + +fun FreenetRequest.toSoneRequest(core: Core, webInterface: WebInterface) = SoneRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager, core, webInterface) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/page/TemplateRenderer.kt b/src/main/kotlin/net/pterodactylus/sone/web/page/TemplateRenderer.kt new file mode 100644 index 0000000..21eeb2a --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/page/TemplateRenderer.kt @@ -0,0 +1,16 @@ +package net.pterodactylus.sone.web.page + +import net.pterodactylus.util.template.* +import java.io.* +import javax.inject.* + +class TemplateRenderer @Inject constructor(private val templateContextFactory: TemplateContextFactory) { + + fun render(template: Template, processor: (TemplateContext) -> Unit = {}): String = + templateContextFactory.createTemplateContext().let { templateContext -> + templateContext.mergeContext(template.initialContext) + processor(templateContext) + StringWriter().also { template.render(templateContext, it) }.toString() + } + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/AboutPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/AboutPage.kt index d3382b4..f622319 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/AboutPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/AboutPage.kt @@ -1,20 +1,21 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.main.SonePlugin.PluginHomepage -import net.pterodactylus.sone.main.SonePlugin.PluginVersion -import net.pterodactylus.sone.main.SonePlugin.PluginYear -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * A [SoneTemplatePage] that stores information about Sone in the [TemplateContext]. */ -class AboutPage(template: Template, webInterface: WebInterface, +@MenuName("About") +@TemplatePath("/templates/about.html") +@ToadletPath("about.html") +class AboutPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer, private val pluginVersion: PluginVersion, private val pluginYear: PluginYear, - private val pluginHomepage: PluginHomepage): SoneTemplatePage("about.html", template, "Page.About.Title", webInterface, false) { + private val pluginHomepage: PluginHomepage) : SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.About.Title") { override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { templateContext["version"] = pluginVersion.version diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt index 7fb2320..1dc12e4 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt @@ -1,23 +1,25 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user bookmark a post. */ -class BookmarkPage(template: Template, webInterface: WebInterface) - : SoneTemplatePage("bookmark.html", template, "Page.Bookmark.Title", webInterface) { +@ToadletPath("bookmark.html") +class BookmarkPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) + : SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Bookmark.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) - val postId = freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36) - webInterface.core.getPost(postId)?.let { - webInterface.core.bookmarkPost(it) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) + val postId = soneRequest.httpRequest.getPartAsStringFailsafe("post", 36) + soneRequest.core.getPost(postId)?.let { + soneRequest.core.bookmarkPost(it) } throw RedirectException(returnPage) } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarksPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarksPage.kt index fbfc7d3..b892263 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarksPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarksPage.kt @@ -1,20 +1,25 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user browse all his bookmarked posts. */ -class BookmarksPage(template: Template, webInterface: WebInterface): SoneTemplatePage("bookmarks.html", template, "Page.Bookmarks.Title", webInterface) { +@MenuName("Bookmarks") +@TemplatePath("/templates/bookmarks.html") +@ToadletPath("bookmarks.html") +class BookmarksPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Bookmarks.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - webInterface.core.bookmarkedPosts.let { posts -> - val pagination = Pagination(posts.filter { it.isLoaded }.sortedByDescending { it.time }, webInterface.core.preferences.postsPerPage) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + soneRequest.core.bookmarkedPosts.let { posts -> + val pagination = posts.filter(Post::isLoaded).sortedByDescending { it.time }.paginate(soneRequest.core.preferences.postsPerPage) templateContext["pagination"] = pagination templateContext["posts"] = pagination.items templateContext["postsNotLoaded"] = posts.any { !it.isLoaded } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt index b0eea08..a00b4bf 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt @@ -1,40 +1,43 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Album.Modifier.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user create a new album. */ -class CreateAlbumPage(template: Template, webInterface: WebInterface): - LoggedInPage("createAlbum.html", template, "Page.CreateAlbum.Title", webInterface) { +@TemplatePath("/templates/createAlbum.html") +@ToadletPath("createAlbum.html") +class CreateAlbumPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.CreateAlbum.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val name = freenetRequest.httpRequest.getPartAsStringFailsafe("name", 64).trim() + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val name = soneRequest.httpRequest.getPartAsStringFailsafe("name", 64).trim() if (name.isEmpty()) { templateContext["nameMissing"] = true return } - val description = freenetRequest.httpRequest.getPartAsStringFailsafe("description", 256).trim() - val parentId = freenetRequest.httpRequest.getPartAsStringFailsafe("parent", 36) - val parent = if (parentId == "") currentSone.rootAlbum else webInterface.core.getAlbum(parentId) - val album = webInterface.core.createAlbum(currentSone, parent) + val description = soneRequest.httpRequest.getPartAsStringFailsafe("description", 256).trim() + val parentId = soneRequest.httpRequest.getPartAsStringFailsafe("parent", 36) + val parent = if (parentId == "") currentSone.rootAlbum else soneRequest.core.getAlbum(parentId) + val album = soneRequest.core.createAlbum(currentSone, parent) try { album.modify().apply { setTitle(name) - setDescription(TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), description)) + setDescription(TextFilter.filter(soneRequest.httpRequest.getHeader("Host"), description)) }.update() } catch (e: AlbumTitleMustNotBeEmpty) { throw RedirectException("emptyAlbumTitle.html") } - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("imageBrowser.html?album=${album.id}") } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt index 31896f7..b47c2b1 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt @@ -1,32 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.asOptional -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user create a new [Post]. */ -class CreatePostPage(template: Template, webInterface: WebInterface): - LoggedInPage("createPost.html", template, "Page.CreatePost.Title", webInterface) { +@TemplatePath("/templates/createPost.html") +@ToadletPath("createPost.html") +class CreatePostPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.CreatePost.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) templateContext["returnPage"] = returnPage - if (freenetRequest.isPOST) { - val text = freenetRequest.httpRequest.getPartAsStringFailsafe("text", 65536).trim() + if (soneRequest.isPOST) { + val text = soneRequest.httpRequest.getPartAsStringFailsafe("text", 65536).trim() if (text == "") { templateContext["errorTextEmpty"] = true return } - val sender = webInterface.core.getLocalSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: currentSone - val recipient = webInterface.core.getSone(freenetRequest.httpRequest.getPartAsStringFailsafe("recipient", 43)) - webInterface.core.createPost(sender, recipient.asOptional(), TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), text)) + val sender = soneRequest.core.getLocalSone(soneRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: currentSone + val recipient = soneRequest.core.getSone(soneRequest.httpRequest.getPartAsStringFailsafe("recipient", 43)) + soneRequest.core.createPost(sender, recipient.asOptional(), TextFilter.filter(soneRequest.httpRequest.getHeader("Host"), text)) throw RedirectException(returnPage) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt index bc6faa4..562e647 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt @@ -1,31 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user post a reply to a post. */ -class CreateReplyPage(template: Template, webInterface: WebInterface): - LoggedInPage("createReply.html", template, "Page.CreateReply.Title", webInterface) { +@TemplatePath("/templates/createReply.html") +@ToadletPath("createReply.html") +class CreateReplyPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.CreateReply.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - val postId = freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36).apply { templateContext["postId"] = this } - val text = freenetRequest.httpRequest.getPartAsStringFailsafe("text", 65536).trim().apply { templateContext["text"] = this } - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256).apply { templateContext["returnPage"] = this } - if (freenetRequest.isPOST) { + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + val postId = soneRequest.httpRequest.getPartAsStringFailsafe("post", 36).apply { templateContext["postId"] = this } + val text = soneRequest.httpRequest.getPartAsStringFailsafe("text", 65536).trim().apply { templateContext["text"] = this } + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256).apply { templateContext["returnPage"] = this } + if (soneRequest.isPOST) { if (text == "") { templateContext["errorTextEmpty"] = true return } - val post = webInterface.core.getPost(postId) ?: throw RedirectException("noPermission.html") - val sender = webInterface.core.getLocalSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: currentSone - webInterface.core.createReply(sender, post, TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), text)) + val post = soneRequest.core.getPost(postId) ?: throw RedirectException("noPermission.html") + val sender = soneRequest.core.getLocalSone(soneRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: currentSone + soneRequest.core.createReply(sender, post, TextFilter.filter(soneRequest.httpRequest.getHeader("Host"), text)) throw RedirectException(returnPage) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateSonePage.kt index efa6f1d..b2056c2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateSonePage.kt @@ -1,45 +1,47 @@ package net.pterodactylus.sone.web.pages -import freenet.clients.http.ToadletContext -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.util.logging.Level -import java.util.logging.Logger +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import java.util.logging.* +import javax.inject.* /** * The “create Sone” page lets the user create a new Sone. */ -class CreateSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("createSone.html", template, "Page.CreateSone.Title", webInterface, false) { +@MenuName("CreateSone") +@TemplatePath("/templates/createSone.html") +@ToadletPath("createSone.html") +class CreateSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.CreateSone.Title") { private val logger = Logger.getLogger(CreateSonePage::class.java.name) - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - templateContext["sones"] = webInterface.core.localSones.sortedWith(Sone.NICE_NAME_COMPARATOR) - templateContext["identitiesWithoutSone"] = webInterface.core.identityManager.allOwnIdentities.filterNot { "Sone" in it.contexts }.sortedBy { "${it.nickname}@${it.id}".toLowerCase() } - if (freenetRequest.isPOST) { - val identity = freenetRequest.httpRequest.getPartAsStringFailsafe("identity", 43) - webInterface.core.identityManager.allOwnIdentities.firstOrNull { it.id == identity }?.let { ownIdentity -> - val sone = webInterface.core.createSone(ownIdentity) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + templateContext["sones"] = soneRequest.core.localSones.sortedWith(Sone.NICE_NAME_COMPARATOR) + templateContext["identitiesWithoutSone"] = soneRequest.core.identityManager.allOwnIdentities.filterNot { "Sone" in it.contexts }.sortedBy { "${it.nickname}@${it.id}".toLowerCase() } + if (soneRequest.isPOST) { + val identity = soneRequest.httpRequest.getPartAsStringFailsafe("identity", 43) + soneRequest.core.identityManager.allOwnIdentities.firstOrNull { it.id == identity }?.let { ownIdentity -> + val sone = soneRequest.core.createSone(ownIdentity) if (sone == null) { logger.log(Level.SEVERE, "Could not create Sone for OwnIdentity: $ownIdentity") } - setCurrentSone(freenetRequest.toadletContext, sone) + setCurrentSone(soneRequest.toadletContext, sone) throw RedirectException("index.html") } templateContext["errorNoIdentity"] = true } } - override fun isEnabled(toadletContext: ToadletContext) = - if (webInterface.core.preferences.isRequireFullAccess && !toadletContext.isAllowedFullAccess) { + override fun isEnabled(soneRequest: SoneRequest) = + if (soneRequest.core.preferences.requireFullAccess && !soneRequest.toadletContext.isAllowedFullAccess) { false } else { - (getCurrentSone(toadletContext) == null) || (webInterface.core.localSones.size == 1) + (getCurrentSone(soneRequest.toadletContext) == null) || (soneRequest.core.localSones.size == 1) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt index eff79b9..d55c7cb 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt @@ -1,31 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user delete an {@link Album}. */ -class DeleteAlbumPage(template: Template, webInterface: WebInterface): - LoggedInPage("deleteAlbum.html", template, "Page.DeleteAlbum.Title", webInterface) { +@TemplatePath("/templates/deleteAlbum.html") +@ToadletPath("deleteAlbum.html") +class DeleteAlbumPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeleteAlbum.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val album = webInterface.core.getAlbum(freenetRequest.httpRequest.getPartAsStringFailsafe("album", 36)) ?: throw RedirectException("invalid.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val album = soneRequest.core.getAlbum(soneRequest.httpRequest.getPartAsStringFailsafe("album", 36)) ?: throw RedirectException("invalid.html") if (!album.sone.isLocal) { throw RedirectException("noPermission.html") } - if (freenetRequest.httpRequest.getPartAsStringFailsafe("abortDelete", 4) == "true") { + if (soneRequest.httpRequest.getPartAsStringFailsafe("abortDelete", 4) == "true") { throw RedirectException("imageBrowser.html?album=${album.id}") } - webInterface.core.deleteAlbum(album) + soneRequest.core.deleteAlbum(album) throw RedirectException(if (album.parent.isRoot) "imageBrowser.html?sone=${album.sone.id}" else "imageBrowser.html?album=${album.parent.id}") } - val album = webInterface.core.getAlbum(freenetRequest.httpRequest.getParam("album")) + val album = soneRequest.core.getAlbum(soneRequest.httpRequest.getParam("album")) templateContext["album"] = album ?: throw RedirectException("invalid.html") } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt index fb77707..a9d601c 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt @@ -1,31 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user delete an {@link Image}. */ -class DeleteImagePage(template: Template, webInterface: WebInterface): - LoggedInPage("deleteImage.html", template, "Page.DeleteImage.Title", webInterface) { +@TemplatePath("/templates/deleteImage.html") +@ToadletPath("deleteImage.html") +class DeleteImagePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeleteImage.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val image = webInterface.core.getImage(freenetRequest.httpRequest.getPartAsStringFailsafe("image", 36)) ?: throw RedirectException("invalid.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val image = soneRequest.core.getImage(soneRequest.httpRequest.getPartAsStringFailsafe("image", 36)) ?: throw RedirectException("invalid.html") if (!image.sone.isLocal) { throw RedirectException("noPermission.html") } - if (freenetRequest.httpRequest.isPartSet("abortDelete")) { + if (soneRequest.httpRequest.isPartSet("abortDelete")) { throw RedirectException("imageBrowser.html?image=${image.id}") } - webInterface.core.deleteImage(image) + soneRequest.core.deleteImage(image) throw RedirectException("imageBrowser.html?album=${image.album.id}") } - val image = webInterface.core.getImage(freenetRequest.httpRequest.getParam("image")) ?: throw RedirectException("invalid.html") + val image = soneRequest.core.getImage(soneRequest.httpRequest.getParam("image")) ?: throw RedirectException("invalid.html") if (!image.sone.isLocal) { throw RedirectException("noPermission.html") } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt index 8eccfb4..b3749b3 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt @@ -1,37 +1,40 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Lets the user delete a post they made. */ -class DeletePostPage(template: Template, webInterface: WebInterface): - LoggedInPage("deletePost.html", template, "Page.DeletePost.Title", webInterface) { +@TemplatePath("/templates/deletePost.html") +@ToadletPath("deletePost.html") +class DeletePostPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeletePost.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val post = webInterface.core.getPost(freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36)) ?: throw RedirectException("noPermission.html") - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val post = soneRequest.core.getPost(soneRequest.httpRequest.getPartAsStringFailsafe("post", 36)) ?: throw RedirectException("noPermission.html") + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) if (!post.sone.isLocal) { throw RedirectException("noPermission.html") } - if (freenetRequest.httpRequest.isPartSet("confirmDelete")) { - webInterface.core.deletePost(post) + if (soneRequest.httpRequest.isPartSet("confirmDelete")) { + soneRequest.core.deletePost(post) throw RedirectException(returnPage) - } else if (freenetRequest.httpRequest.isPartSet("abortDelete")) { + } else if (soneRequest.httpRequest.isPartSet("abortDelete")) { throw RedirectException(returnPage) } templateContext["post"] = post templateContext["returnPage"] = returnPage return } - templateContext["post"] = webInterface.core.getPost(freenetRequest.httpRequest.getParam("post")) ?: throw RedirectException("noPermission.html") - templateContext["returnPage"] = freenetRequest.httpRequest.getParam("returnPage") + templateContext["post"] = soneRequest.core.getPost(soneRequest.httpRequest.getParam("post")) ?: throw RedirectException("noPermission.html") + templateContext["returnPage"] = soneRequest.httpRequest.getParam("returnPage") } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt index f25299f..0fabad9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt @@ -1,27 +1,30 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user confirm the deletion of a profile field. */ -class DeleteProfileFieldPage(template: Template, webInterface: WebInterface): - LoggedInPage("deleteProfileField.html", template, "Page.DeleteProfileField.Title", webInterface) { +@TemplatePath("/templates/deleteProfileField.html") +@ToadletPath("deleteProfileField.html") +class DeleteProfileFieldPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeleteProfileField.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val field = currentSone.profile.getFieldById(freenetRequest.httpRequest.getPartAsStringFailsafe("field", 36)) ?: throw RedirectException("invalid.html") - if (freenetRequest.httpRequest.getPartAsStringFailsafe("confirm", 4) == "true") { + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val field = currentSone.profile.getFieldById(soneRequest.httpRequest.getPartAsStringFailsafe("field", 36)) ?: throw RedirectException("invalid.html") + if (soneRequest.httpRequest.getPartAsStringFailsafe("confirm", 4) == "true") { currentSone.profile = currentSone.profile.apply { removeField(field) } } throw RedirectException("editProfile.html#profile-fields") } - val field = currentSone.profile.getFieldById(freenetRequest.httpRequest.getParam("field")) ?: throw RedirectException("invalid.html") + val field = currentSone.profile.getFieldById(soneRequest.httpRequest.getParam("field")) ?: throw RedirectException("invalid.html") templateContext["field"] = field } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt index 29d8c81..e3f30ce 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt @@ -1,39 +1,42 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user delete a reply. */ -class DeleteReplyPage(template: Template, webInterface: WebInterface): - LoggedInPage("deleteReply.html", template, "Page.DeleteReply.Title", webInterface) { +@TemplatePath("/templates/deleteReply.html") +@ToadletPath("deleteReply.html") +class DeleteReplyPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeleteReply.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val replyId = freenetRequest.httpRequest.getPartAsStringFailsafe("reply", 36) - val reply = webInterface.core.getPostReply(replyId) ?: throw RedirectException("noPermission.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val replyId = soneRequest.httpRequest.getPartAsStringFailsafe("reply", 36) + val reply = soneRequest.core.getPostReply(replyId) ?: throw RedirectException("noPermission.html") if (!reply.sone.isLocal) { throw RedirectException("noPermission.html") } - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) - if (freenetRequest.httpRequest.isPartSet("confirmDelete")) { - webInterface.core.deleteReply(reply) + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) + if (soneRequest.httpRequest.isPartSet("confirmDelete")) { + soneRequest.core.deleteReply(reply) throw RedirectException(returnPage) } - if (freenetRequest.httpRequest.isPartSet("abortDelete")) { + if (soneRequest.httpRequest.isPartSet("abortDelete")) { throw RedirectException(returnPage) } templateContext["reply"] = replyId templateContext["returnPage"] = returnPage return } - templateContext["reply"] = freenetRequest.httpRequest.getParam("reply") - templateContext["returnPage"] = freenetRequest.httpRequest.getParam("returnPage") + templateContext["reply"] = soneRequest.httpRequest.getParam("reply") + templateContext["returnPage"] = soneRequest.httpRequest.getParam("returnPage") } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt index b2a6d7b..f65e378 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt @@ -1,24 +1,28 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Lets the user delete a Sone. Of course the Sone is not really deleted from * Freenet; merely all references to it are removed from the local plugin * installation. */ -class DeleteSonePage(template: Template, webInterface: WebInterface): - LoggedInPage("deleteSone.html", template, "Page.DeleteSone.Title", webInterface) { +@MenuName("DeleteSone") +@TemplatePath("/templates/deleteSone.html") +@ToadletPath("deleteSone.html") +class DeleteSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.DeleteSone.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - if (freenetRequest.httpRequest.isPartSet("deleteSone")) { - webInterface.core.deleteSone(currentSone) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + if (soneRequest.httpRequest.isPartSet("deleteSone")) { + soneRequest.core.deleteSone(currentSone) } throw RedirectException("index.html") } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPage.kt index 78cdb83..862db67 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPage.kt @@ -1,20 +1,22 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user dismiss a notification. */ -class DismissNotificationPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("dismissNotification.html", template, "Page.DismissNotification.Title", webInterface) { +@ToadletPath("dismissNotification.html") +class DismissNotificationPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.DismissNotification.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) - val notificationId = freenetRequest.httpRequest.getPartAsStringFailsafe("notification", 36) - webInterface.getNotification(notificationId).orNull()?.takeIf { it.isDismissable }?.dismiss() + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + val returnPage = soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) + val notificationId = soneRequest.httpRequest.getPartAsStringFailsafe("notification", 36) + soneRequest.webInterface.getNotification(notificationId).orNull()?.takeIf { it.isDismissable }?.dismiss() throw RedirectException(returnPage) } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt index 70755f5..f2115e5 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt @@ -1,11 +1,12 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user distrust another Sone. This will assign a @@ -13,14 +14,15 @@ import net.pterodactylus.util.template.TemplateContext * * @see net.pterodactylus.sone.core.Core#distrustSone(Sone, Sone) */ -class DistrustPage(template: Template, webInterface: WebInterface): - LoggedInPage("distrust.html", template, "Page.Distrust.Title", webInterface) { +@ToadletPath("distrust.html") +class DistrustPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Distrust.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - webInterface.core.getSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sone", 44)) - ?.run { webInterface.core.distrustSone(currentSone, this) } - throw RedirectException(freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256)) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.core.getSone(soneRequest.httpRequest.getPartAsStringFailsafe("sone", 44)) + ?.run { soneRequest.core.distrustSone(currentSone, this) } + throw RedirectException(soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256)) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt index 26d7c3a..aeaf14e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt @@ -1,41 +1,43 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Album.Modifier.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user edit the name and description of an album. */ -class EditAlbumPage(template: Template, webInterface: WebInterface): - LoggedInPage("editAlbum.html", template, "Page.EditAlbum.Title", webInterface) { +@ToadletPath("editAlbum.html") +class EditAlbumPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.EditAlbum.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val album = webInterface.core.getAlbum(freenetRequest.httpRequest.getPartAsStringFailsafe("album", 36)) ?: throw RedirectException("invalid.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val album = soneRequest.core.getAlbum(soneRequest.httpRequest.getPartAsStringFailsafe("album", 36)) ?: throw RedirectException("invalid.html") album.takeUnless { it.sone.isLocal }?.run { throw RedirectException("noPermission.html") } - if (freenetRequest.httpRequest.getPartAsStringFailsafe("moveLeft", 4) == "true") { + if (soneRequest.httpRequest.getPartAsStringFailsafe("moveLeft", 4) == "true") { album.parent?.moveAlbumUp(album) - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("imageBrowser.html?album=${album.parent?.id}") - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("moveRight", 4) == "true") { + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("moveRight", 4) == "true") { album.parent?.moveAlbumDown(album) - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("imageBrowser.html?album=${album.parent?.id}") } else { try { album.modify() - .setTitle(freenetRequest.httpRequest.getPartAsStringFailsafe("title", 100)) - .setDescription(freenetRequest.httpRequest.getPartAsStringFailsafe("description", 1000)) + .setTitle(soneRequest.httpRequest.getPartAsStringFailsafe("title", 100)) + .setDescription(soneRequest.httpRequest.getPartAsStringFailsafe("description", 1000)) .update() } catch (e: AlbumTitleMustNotBeEmpty) { throw RedirectException("emptyAlbumTitle.html") } - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("imageBrowser.html?album=${album.id}") } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt index 350dec7..76f6e23 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt @@ -1,40 +1,42 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Image.Modifier.ImageTitleMustNotBeEmpty -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Image.Modifier.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user edit title and description of an {@link Image}. */ -class EditImagePage(template: Template, webInterface: WebInterface): - LoggedInPage("editImage.html", template, "Page.EditImage.Title", webInterface) { +@ToadletPath("editImage.html") +class EditImagePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.EditImage.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val image = webInterface.core.getImage(freenetRequest.httpRequest.getPartAsStringFailsafe("image", 36)) ?: throw RedirectException("invalid.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val image = soneRequest.core.getImage(soneRequest.httpRequest.getPartAsStringFailsafe("image", 36)) ?: throw RedirectException("invalid.html") if (!image.sone.isLocal) { throw RedirectException("noPermission.html") } - freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256).let { returnPage -> - if (freenetRequest.httpRequest.getPartAsStringFailsafe("moveLeft", 4) == "true") { + soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256).let { returnPage -> + if (soneRequest.httpRequest.getPartAsStringFailsafe("moveLeft", 4) == "true") { image.album.moveImageUp(image) - webInterface.core.touchConfiguration() - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("moveRight", 4) == "true") { + soneRequest.core.touchConfiguration() + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("moveRight", 4) == "true") { image.album.moveImageDown(image) - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() } else { try { image.modify() - .setTitle(freenetRequest.httpRequest.getPartAsStringFailsafe("title", 100)) - .setDescription(TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), freenetRequest.httpRequest.getPartAsStringFailsafe("description", 1024))) + .setTitle(soneRequest.httpRequest.getPartAsStringFailsafe("title", 100)) + .setDescription(TextFilter.filter(soneRequest.httpRequest.getHeader("Host"), soneRequest.httpRequest.getPartAsStringFailsafe("description", 1024))) .update() - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() } catch (e: ImageTitleMustNotBeEmpty) { throw RedirectException("emptyImageTitle.html") } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt index f3486d2..386f66b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt @@ -1,26 +1,29 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user edit the name of a profile field. */ -class EditProfileFieldPage(template: Template, webInterface: WebInterface) : - LoggedInPage("editProfileField.html", template, "Page.EditProfileField.Title", webInterface) { +@TemplatePath("/templates/editProfileField.html") +@ToadletPath("editProfileField.html") +class EditProfileFieldPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.EditProfileField.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { currentSone.profile.let { profile -> - if (freenetRequest.isPOST) { - if (freenetRequest.httpRequest.getPartAsStringFailsafe("cancel", 4) == "true") { + if (soneRequest.isPOST) { + if (soneRequest.httpRequest.getPartAsStringFailsafe("cancel", 4) == "true") { throw RedirectException("editProfile.html#profile-fields") } - val field = profile.getFieldById(freenetRequest.httpRequest.getPartAsStringFailsafe("field", 36)) ?: throw RedirectException("invalid.html") - freenetRequest.httpRequest.getPartAsStringFailsafe("name", 256).let { name -> + val field = profile.getFieldById(soneRequest.httpRequest.getPartAsStringFailsafe("field", 36)) ?: throw RedirectException("invalid.html") + soneRequest.httpRequest.getPartAsStringFailsafe("name", 256).let { name -> try { if (name != field.name) { field.name = name @@ -33,7 +36,7 @@ class EditProfileFieldPage(template: Template, webInterface: WebInterface) : } } } - templateContext["field"] = profile.getFieldById(freenetRequest.httpRequest.getParam("field")) ?: throw RedirectException("invalid.html") + templateContext["field"] = profile.getFieldById(soneRequest.httpRequest.getParam("field")) ?: throw RedirectException("invalid.html") } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt index 95c40c8..54b7efd 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt @@ -1,21 +1,25 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Profile.DuplicateField -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Profile.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user edit her profile. */ -class EditProfilePage(template: Template, webInterface: WebInterface) : - LoggedInPage("editProfile.html", template, "Page.EditProfile.Title", webInterface) { +@MenuName("EditProfile") +@TemplatePath("/templates/editProfile.html") +@ToadletPath("editProfile.html") +class EditProfilePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.EditProfile.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { currentSone.profile.let { profile -> templateContext["firstName"] = profile.firstName templateContext["middleName"] = profile.middleName @@ -25,42 +29,42 @@ class EditProfilePage(template: Template, webInterface: WebInterface) : templateContext["birthYear"] = profile.birthYear templateContext["avatarId"] = profile.avatar templateContext["fields"] = profile.fields - if (freenetRequest.isPOST) { - if (freenetRequest.httpRequest.getPartAsStringFailsafe("save-profile", 4) == "true") { - profile.firstName = freenetRequest.httpRequest.getPartAsStringFailsafe("first-name", 256).trim() - profile.middleName = freenetRequest.httpRequest.getPartAsStringFailsafe("middle-name", 256).trim() - profile.lastName = freenetRequest.httpRequest.getPartAsStringFailsafe("last-name", 256).trim() - profile.birthDay = freenetRequest.httpRequest.getPartAsStringFailsafe("birth-day", 256).trim().toIntOrNull() - profile.birthMonth = freenetRequest.httpRequest.getPartAsStringFailsafe("birth-month", 256).trim().toIntOrNull() - profile.birthYear = freenetRequest.httpRequest.getPartAsStringFailsafe("birth-year", 256).trim().toIntOrNull() - profile.setAvatar(webInterface.core.getImage(freenetRequest.httpRequest.getPartAsStringFailsafe("avatarId", 256).trim(), false)) + if (soneRequest.isPOST) { + if (soneRequest.httpRequest.getPartAsStringFailsafe("save-profile", 4) == "true") { + profile.firstName = soneRequest.httpRequest.getPartAsStringFailsafe("first-name", 256).trim() + profile.middleName = soneRequest.httpRequest.getPartAsStringFailsafe("middle-name", 256).trim() + profile.lastName = soneRequest.httpRequest.getPartAsStringFailsafe("last-name", 256).trim() + profile.birthDay = soneRequest.httpRequest.getPartAsStringFailsafe("birth-day", 256).trim().toIntOrNull() + profile.birthMonth = soneRequest.httpRequest.getPartAsStringFailsafe("birth-month", 256).trim().toIntOrNull() + profile.birthYear = soneRequest.httpRequest.getPartAsStringFailsafe("birth-year", 256).trim().toIntOrNull() + profile.setAvatar(soneRequest.core.getImage(soneRequest.httpRequest.getPartAsStringFailsafe("avatarId", 256).trim(), false)) profile.fields.forEach { field -> - field.value = TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), freenetRequest.httpRequest.getPartAsStringFailsafe("field-${field.id}", 400).trim()) + field.value = TextFilter.filter(soneRequest.httpRequest.getHeader("Host"), soneRequest.httpRequest.getPartAsStringFailsafe("field-${field.id}", 400).trim()) } currentSone.profile = profile - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("editProfile.html") - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("add-field", 4) == "true") { - val fieldName = freenetRequest.httpRequest.getPartAsStringFailsafe("field-name", 100) + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("add-field", 4) == "true") { + val fieldName = soneRequest.httpRequest.getPartAsStringFailsafe("field-name", 100) try { profile.addField(fieldName) currentSone.profile = profile - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("editProfile.html#profile-fields") } catch (e: DuplicateField) { templateContext["fieldName"] = fieldName templateContext["duplicateFieldName"] = true } } else profile.fields.forEach { field -> - if (freenetRequest.httpRequest.getPartAsStringFailsafe("delete-field-${field.id}", 4) == "true") { + if (soneRequest.httpRequest.getPartAsStringFailsafe("delete-field-${field.id}", 4) == "true") { throw RedirectException("deleteProfileField.html?field=${field.id}") - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("edit-field-${field.id}", 4) == "true") { + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("edit-field-${field.id}", 4) == "true") { throw RedirectException("editProfileField.html?field=${field.id}") - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("move-down-field-${field.id}", 4) == "true") { + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("move-down-field-${field.id}", 4) == "true") { profile.moveFieldDown(field) currentSone.profile = profile throw RedirectException("editProfile.html#profile-fields") - } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("move-up-field-${field.id}", 4) == "true") { + } else if (soneRequest.httpRequest.getPartAsStringFailsafe("move-up-field-${field.id}", 4) == "true") { profile.moveFieldUp(field) currentSone.profile = profile throw RedirectException("editProfile.html#profile-fields") diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/ErrorPages.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/ErrorPages.kt new file mode 100644 index 0000000..8d52c87 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ErrorPages.kt @@ -0,0 +1,21 @@ +package net.pterodactylus.sone.web.pages + +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* + +@TemplatePath("/templates/invalid.html") +@ToadletPath("invalid.html") +class InvalidPage(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : SoneTemplatePage(webInterface, loaders, templateRenderer, "Page.Invalid.Title") + +@TemplatePath("/templates/noPermission.html") +@ToadletPath("noPermission.html") +class NoPermissionPage(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : SoneTemplatePage(webInterface, loaders, templateRenderer, "Page.NoPermission.Title") + +@TemplatePath("/templates/emptyImageTitle.html") +@ToadletPath("emptyImageTitle.html") +class EmptyImageTitlePage(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : SoneTemplatePage(webInterface, loaders, templateRenderer, "Page.EmptyImageTitle.Title") + +@TemplatePath("/templates/emptyAlbumTitle.html") +@ToadletPath("emptyAlbumTitle.html") +class EmptyAlbumTitlePage(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : SoneTemplatePage(webInterface, loaders, templateRenderer, "Page.EmptyAlbumTitle.Title") diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt index cf5bcee..244cb52 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt @@ -1,28 +1,30 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user follow another Sone. */ -class FollowSonePage(template: Template, webInterface: WebInterface): - LoggedInPage("followSone.html", template, "Page.FollowSone.Title", webInterface) { +@ToadletPath("followSone.html") +class FollowSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.FollowSone.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - freenetRequest.httpRequest.getPartAsStringFailsafe("sone", 1200).split(Regex("[ ,]+")) - .map { it to webInterface.core.getSone(it) } + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.httpRequest.getPartAsStringFailsafe("sone", 1200).split(Regex("[ ,]+")) + .map { it to soneRequest.core.getSone(it) } .filterNot { it.second == null } .forEach { sone -> - webInterface.core.followSone(currentSone, sone.first) - webInterface.core.markSoneKnown(sone.second) + soneRequest.core.followSone(currentSone, sone.first) + soneRequest.core.markSoneKnown(sone.second) } - throw RedirectException(freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256)) + throw RedirectException(soneRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256)) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/GetImagePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/GetImagePage.kt index 932827e..f7857c3 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/GetImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/GetImagePage.kt @@ -1,15 +1,15 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetPage -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.web.Response -import java.net.URI +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.* +import java.net.* +import javax.inject.* /** * Page that delivers a {@link TemporaryImage} to the browser. */ -class GetImagePage(webInterface: WebInterface): FreenetPage { +class GetImagePage @Inject constructor(webInterface: WebInterface) : FreenetPage { private val core = webInterface.core @@ -35,7 +35,7 @@ class GetImagePage(webInterface: WebInterface): FreenetPage { } } - override fun isLinkExcepted(link: URI?): Boolean { + override fun isLinkExcepted(link: URI): Boolean { return false } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt index e9911e6..20219d7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt @@ -1,49 +1,53 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.net.URI +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import java.net.* +import javax.inject.* /** * The image browser page is the entry page for the image management. */ -class ImageBrowserPage(template: Template, webInterface: WebInterface): - LoggedInPage("imageBrowser.html", template, "Page.ImageBrowser.Title", webInterface) { +@MenuName("ImageBrowser") +@TemplatePath("/templates/imageBrowser.html") +@ToadletPath("imageBrowser.html") +class ImageBrowserPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.ImageBrowser.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if ("album" in freenetRequest.parameters) { + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if ("album" in soneRequest.parameters) { templateContext["albumRequested"] = true - templateContext["album"] = webInterface.core.getAlbum(freenetRequest.parameters["album"]!!) - templateContext["page"] = freenetRequest.parameters["page"] - } else if ("image" in freenetRequest.parameters) { + templateContext["album"] = soneRequest.core.getAlbum(soneRequest.parameters["album"]!!) + templateContext["page"] = soneRequest.parameters["page"] + } else if ("image" in soneRequest.parameters) { templateContext["imageRequested"] = true - templateContext["image"] = webInterface.core.getImage(freenetRequest.parameters["image"]) - } else if (freenetRequest.parameters["mode"] == "gallery") { + templateContext["image"] = soneRequest.core.getImage(soneRequest.parameters["image"]) + } else if (soneRequest.parameters["mode"] == "gallery") { templateContext["galleryRequested"] = true - webInterface.core.sones + soneRequest.core.sones .map(Sone::getRootAlbum) .flatMap(Album::getAlbums) .flatMap { Album.FLATTENER.apply(it)!! } .filterNot(Album::isEmpty) .sortedBy(Album::getTitle) .also { albums -> - Pagination(albums, webInterface.core.preferences.imagesPerPage).apply { page = freenetRequest.parameters["page"]?.toIntOrNull() ?: 0 }.also { pagination -> - templateContext["albumPagination"] = pagination - templateContext["albums"] = pagination.items - } + albums.paginate(soneRequest.core.preferences.imagesPerPage) + .turnTo(soneRequest.parameters["page"]?.toIntOrNull() ?: 0) + .also { pagination -> + templateContext["albumPagination"] = pagination + templateContext["albums"] = pagination.items + } } } else { templateContext["soneRequested"] = true - templateContext["sone"] = webInterface.core.getSone(freenetRequest.httpRequest.getParam("sone")) ?: currentSone + templateContext["sone"] = soneRequest.core.getSone(soneRequest.httpRequest.getParam("sone")) ?: currentSone } } - override fun isLinkExcepted(link: URI?) = true + override fun isLinkExcepted(link: URI) = true } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt index 0257cb1..069ef9f 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt @@ -1,38 +1,41 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.notify.PostVisibilityFilter -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.notify.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * The index page shows the main page of Sone. This page will contain the posts * of all friends of the current user. */ -class IndexPage(template: Template, webInterface: WebInterface, private val postVisibilityFilter: PostVisibilityFilter): - LoggedInPage("index.html", template, "Page.Index.Title", webInterface) { +@MenuName("Index") +@TemplatePath("/templates/index.html") +@ToadletPath("index.html") +class IndexPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer, private val postVisibilityFilter: PostVisibilityFilter) : + LoggedInPage("Page.Index.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - (currentSone.posts + - currentSone.friends - .mapNotNull(webInterface.core::getSone) - .flatMap { it.posts } + - webInterface.core.getDirectedPosts(currentSone.id) - ).distinct() - .filter { postVisibilityFilter.isVisible(currentSone).apply(it) } - .sortedByDescending { it.time } - .let { posts -> - Pagination(posts, webInterface.core.preferences.postsPerPage).apply { - page = freenetRequest.parameters["page"]?.toIntOrNull() ?: 0 - }.let { pagination -> - templateContext["pagination"] = pagination - templateContext["posts"] = pagination.items - } - } + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + (currentSone.posts + + currentSone.friends + .mapNotNull(soneRequest.core::getSone) + .flatMap { it.posts } + + soneRequest.core.getDirectedPosts(currentSone.id) + ).distinct() + .filter { postVisibilityFilter.isVisible(currentSone).apply(it) } + .sortedByDescending { it.time } + .let { posts -> + posts.paginate(soneRequest.core.preferences.postsPerPage) + .turnTo(soneRequest.parameters["page"]?.toIntOrNull() ?: 0) + .let { pagination -> + templateContext["pagination"] = pagination + templateContext["posts"] = pagination.items + } + } } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPage.kt index 9d6930d..ae0d7d1 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPage.kt @@ -1,48 +1,52 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page shows all known Sones. */ -class KnownSonesPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("knownSones.html", template, "Page.KnownSones.Title", webInterface, false) { +@MenuName("KnownSones") +@TemplatePath("/templates/knownSones.html") +@ToadletPath("knownSones.html") +class KnownSonesPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.KnownSones.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - getCurrentSone(freenetRequest.toadletContext).let { currentSone -> - Pagination(webInterface.core.sones - .filterNot { freenetRequest.parameters["filter"] == "followed" && currentSone != null && !currentSone.hasFriend(it.id) } - .filterNot { freenetRequest.parameters["filter"] == "not-followed" && currentSone != null && currentSone.hasFriend(it.id) } - .filterNot { freenetRequest.parameters["filter"] == "new" && it.isKnown } - .filterNot { freenetRequest.parameters["filter"] == "not-new" && !it.isKnown } - .filterNot { freenetRequest.parameters["filter"] == "own" && !it.isLocal } - .filterNot { freenetRequest.parameters["filter"] == "not-own" && it.isLocal } + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + getCurrentSone(soneRequest.toadletContext).let { currentSone -> + soneRequest.core.sones.asSequence() + .filterNot { soneRequest.parameters["filter"] == "followed" && currentSone != null && !currentSone.hasFriend(it.id) } + .filterNot { soneRequest.parameters["filter"] == "not-followed" && currentSone != null && currentSone.hasFriend(it.id) } + .filterNot { soneRequest.parameters["filter"] == "new" && it.isKnown } + .filterNot { soneRequest.parameters["filter"] == "not-new" && !it.isKnown } + .filterNot { soneRequest.parameters["filter"] == "own" && !it.isLocal } + .filterNot { soneRequest.parameters["filter"] == "not-own" && it.isLocal } .sortedWith( - when (freenetRequest.parameters["sort"]) { + when (soneRequest.parameters["sort"]) { "images" -> Sone.IMAGE_COUNT_COMPARATOR "name" -> Sone.NICE_NAME_COMPARATOR.reversed() "posts" -> Sone.POST_COUNT_COMPARATOR else -> Sone.LAST_ACTIVITY_COMPARATOR }.let { comparator -> - when (freenetRequest.parameters["order"]) { + when (soneRequest.parameters["order"]) { "asc" -> comparator.reversed() else -> comparator } } - ), 25).apply { page = freenetRequest.parameters["page"]?.toIntOrNull() ?: 0 } + ).paginate(25) + .turnTo(soneRequest.parameters["page"]?.toIntOrNull() ?: 0) .let { pagination -> templateContext["pagination"] = pagination templateContext["knownSones"] = pagination.items } - templateContext["sort"] = freenetRequest.parameters["sort"].let { sort -> if (sort in listOf("images", "name", "posts")) sort else "activity" } - templateContext["order"] = freenetRequest.parameters["order"].let { order -> if (order == "asc") "asc" else "desc" } - templateContext["filter"] = freenetRequest.parameters["filter"] + templateContext["sort"] = soneRequest.parameters["sort"].let { sort -> if (sort in listOf("images", "name", "posts")) sort else "activity" } + templateContext["order"] = soneRequest.parameters["order"].let { order -> if (order == "asc") "asc" else "desc" } + templateContext["filter"] = soneRequest.parameters["filter"] } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt index ef622df..cc5043f 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt @@ -1,28 +1,29 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user like [net.pterodactylus.sone.data.Post]s and [net.pterodactylus.sone.data.Reply]s. */ -class LikePage(template: Template, webInterface: WebInterface) : - LoggedInPage("like.html", template, "Page.Like.Title", webInterface) { +@ToadletPath("like.html") +class LikePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Like.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - freenetRequest.parameters["type", 16]?.also { type -> + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.parameters["type", 16]?.also { type -> when (type) { - "post" -> currentSone.addLikedPostId(freenetRequest.parameters["post", 36]!!) - "reply" -> currentSone.addLikedReplyId(freenetRequest.parameters["reply", 36]!!) + "post" -> currentSone.addLikedPostId(soneRequest.parameters["post", 36]!!) + "reply" -> currentSone.addLikedReplyId(soneRequest.parameters["reply", 36]!!) } } - throw RedirectException(freenetRequest.parameters["returnPage", 256]!!) + throw RedirectException(soneRequest.parameters["returnPage", 256]!!) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LockSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LockSonePage.kt index 835fe23..2a62a7d 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LockSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LockSonePage.kt @@ -1,22 +1,24 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user lock a [net.pterodactylus.sone.data.Sone] to prevent it from being inserted. */ -class LockSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("lockSone.html", template, "Page.LockSone.Title", webInterface, false) { +@ToadletPath("lockSone.html") +class LockSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.LockSone.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - freenetRequest.parameters["returnPage", 256]!!.let { returnPage -> - freenetRequest.parameters["sone", 44]!! - .let { webInterface.core.getLocalSone(it) } - ?.let { webInterface.core.lockSone(it) } + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + soneRequest.parameters["returnPage", 256]!!.let { returnPage -> + soneRequest.parameters["sone", 44]!! + .let { soneRequest.core.getLocalSone(it) } + ?.let { soneRequest.core.lockSone(it) } throw RedirectException(returnPage) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt index c88499e..5d389b9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt @@ -1,21 +1,21 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* /** * Base class for [SoneTemplatePage] implementations that require a logged in user. */ -abstract class LoggedInPage(path: String, template: Template, pageTitleKey: String, webInterface: WebInterface) : - SoneTemplatePage(path, template, pageTitleKey, webInterface, true) { +abstract class LoggedInPage(pageTitleKey: String, webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = pageTitleKey, requiresLogin = true) { - final override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - handleRequest(freenetRequest, getCurrentSone(freenetRequest.toadletContext, false)!!, templateContext) + final override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + handleRequest(soneRequest, getCurrentSone(soneRequest.toadletContext, false)!!, templateContext) } - protected abstract fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) + protected abstract fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LoginPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoginPage.kt index 0e0fee5..9e47049 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LoginPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoginPage.kt @@ -1,39 +1,41 @@ package net.pterodactylus.sone.web.pages -import freenet.clients.http.ToadletContext -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * The login page lets the user log in. */ -class LoginPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("login.html", template, "Page.Login.Title", webInterface) { +@MenuName("Login") +@TemplatePath("/templates/login.html") +@ToadletPath("login.html") +class LoginPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Login.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val soneId = freenetRequest.httpRequest.getPartAsStringFailsafe("sone-id", 43) - webInterface.core.getLocalSone(soneId)?.let { sone -> - setCurrentSone(freenetRequest.toadletContext, sone) - val target = freenetRequest.httpRequest.getParam("target").emptyToNull ?: "index.html" + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val soneId = soneRequest.httpRequest.getPartAsStringFailsafe("sone-id", 43) + soneRequest.core.getLocalSone(soneId)?.let { sone -> + setCurrentSone(soneRequest.toadletContext, sone) + val target = soneRequest.httpRequest.getParam("target").emptyToNull ?: "index.html" throw RedirectException(target) } } - templateContext["sones"] = webInterface.core.localSones.sortedWith(Sone.NICE_NAME_COMPARATOR) - templateContext["identitiesWithoutSone"] = webInterface.core.identityManager.allOwnIdentities.filterNot { "Sone" in it.contexts }.sortedBy { "${it.nickname}@${it.id}" } + templateContext["sones"] = soneRequest.core.localSones.sortedWith(Sone.NICE_NAME_COMPARATOR) + templateContext["identitiesWithoutSone"] = soneRequest.core.identityManager.allOwnIdentities.filterNot { "Sone" in it.contexts }.sortedBy { "${it.nickname}@${it.id}" } } - override public fun getRedirectTarget(freenetRequest: FreenetRequest) = - getCurrentSone(freenetRequest.toadletContext)?.let { "index.html" } + override fun getRedirectTarget(request: FreenetRequest) = + getCurrentSone(request.toadletContext)?.let { "index.html" } - override fun isEnabled(toadletContext: ToadletContext) = when { - webInterface.core.preferences.isRequireFullAccess && !toadletContext.isAllowedFullAccess -> false - else -> getCurrentSone(toadletContext, false) == null + override fun isEnabled(soneRequest: SoneRequest) = when { + soneRequest.core.preferences.requireFullAccess && !soneRequest.toadletContext.isAllowedFullAccess -> false + else -> getCurrentSone(soneRequest.toadletContext, false) == null } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt index 7e608ff..325d876 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt @@ -1,27 +1,29 @@ package net.pterodactylus.sone.web.pages -import freenet.clients.http.ToadletContext -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Logs a user out. */ -class LogoutPage(template: Template, webInterface: WebInterface): - LoggedInPage("logout.html", template, "Page.Logout.Title", webInterface) { +@MenuName("Logout") +@ToadletPath("logout.html") +class LogoutPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Logout.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - setCurrentSone(freenetRequest.toadletContext, null) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + setCurrentSone(soneRequest.toadletContext, null) throw RedirectException("index.html") } - override fun isEnabled(toadletContext: ToadletContext): Boolean = - if (webInterface.core.preferences.isRequireFullAccess && !toadletContext.isAllowedFullAccess) { + override fun isEnabled(soneRequest: SoneRequest): Boolean = + if (soneRequest.core.preferences.requireFullAccess && !soneRequest.toadletContext.isAllowedFullAccess) { false } else - getCurrentSone(toadletContext) != null && webInterface.core.localSones.size != 1 + getCurrentSone(soneRequest.toadletContext) != null && soneRequest.core.localSones.size != 1 } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt index 49c1075..652881d 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt @@ -1,29 +1,30 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.utils.mapPresent -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user mark a number of [net.pterodactylus.sone.data.Sone]s, [Post]s, or * [Replie][net.pterodactylus.sone.data.Reply]s as known. */ -class MarkAsKnownPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("markAsKnown.html", template, "Page.MarkAsKnown.Title", webInterface, false) { +@ToadletPath("markAsKnown.html") +class MarkAsKnownPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.MarkAsKnown.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - val ids = freenetRequest.parameters["id", 65536]!!.split(" ") - when (freenetRequest.parameters["type", 5]) { - "sone" -> ids.mapNotNull(webInterface.core::getSone).forEach(webInterface.core::markSoneKnown) - "post" -> ids.mapNotNull(webInterface.core::getPost).forEach(webInterface.core::markPostKnown) - "reply" -> ids.mapNotNull(webInterface.core::getPostReply).forEach(webInterface.core::markReplyKnown) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + val ids = soneRequest.parameters["id", 65536]!!.split(" ") + when (soneRequest.parameters["type", 5]) { + "sone" -> ids.mapNotNull(soneRequest.core::getSone).forEach(soneRequest.core::markSoneKnown) + "post" -> ids.mapNotNull(soneRequest.core::getPost).forEach(soneRequest.core::markPostKnown) + "reply" -> ids.mapNotNull(soneRequest.core::getPostReply).forEach(soneRequest.core::markReplyKnown) else -> throw RedirectException("invalid.html") } - throw RedirectException(freenetRequest.parameters["returnPage", 256]!!) + throw RedirectException(soneRequest.parameters["returnPage", 256]!!) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/NewPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/NewPage.kt index 55df67a..940e6e8 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/NewPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/NewPage.kt @@ -1,32 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.mapPresent -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that displays all new posts and replies. The posts are filtered using * [PostVisibilityFilter.isPostVisible(Sone, Post)] and sorted by time. */ -class NewPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("new.html", template, "Page.New.Title", webInterface, false) { +@MenuName("New") +@TemplatePath("/templates/new.html") +@ToadletPath("new.html") +class NewPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.New.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) = - getCurrentSone(freenetRequest.toadletContext).let { currentSone -> - (webInterface.getNewPosts(currentSone) + webInterface.getNewReplies(currentSone).mapPresent { it.post }) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) = + getCurrentSone(soneRequest.toadletContext).let { currentSone -> + (soneRequest.webInterface.getNewPosts(currentSone) + soneRequest.webInterface.getNewReplies(currentSone).mapPresent { it.post }) .distinct() .sortedByDescending { it.time } .let { posts -> - Pagination(posts, webInterface.core.preferences.postsPerPage).apply { - page = freenetRequest.parameters["page"]?.toIntOrNull() ?: 0 - }.let { pagination -> - templateContext["pagination"] = pagination - templateContext["posts"] = pagination.items - } + posts.paginate(soneRequest.core.preferences.postsPerPage) + .turnTo(soneRequest.parameters["page"]?.toIntOrNull() ?: 0) + .let { pagination -> + templateContext["pagination"] = pagination + templateContext["posts"] = pagination.items + } } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/OptionsPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/OptionsPage.kt index 7cf1bb3..8829030 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/OptionsPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/OptionsPage.kt @@ -1,33 +1,34 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.core.Preferences -import net.pterodactylus.sone.data.SoneOptions.LoadExternalContent -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.SoneOptions.* +import net.pterodactylus.sone.fcp.FcpInterface.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user edit the options of the Sone plugin. */ -class OptionsPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("options.html", template, "Page.Options.Title", webInterface, false) { +@MenuName("Options") +@TemplatePath("/templates/options.html") +@ToadletPath("options.html") +class OptionsPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Options.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + if (soneRequest.isPOST) { val fieldsWithErrors = mutableListOf() - getCurrentSone(freenetRequest.toadletContext)?.options?.let { options -> - val autoFollow = "auto-follow" in freenetRequest.parameters - val loadLinkedImages = freenetRequest.parameters["load-linked-images"].emptyToNull - val showCustomAvatars = freenetRequest.parameters["show-custom-avatars"].emptyToNull - val enableSoneInsertNotification = "enable-sone-insert-notifications" in freenetRequest.parameters - val showNewSoneNotification = "show-notification-new-sones" in freenetRequest.parameters - val showNewPostNotification = "show-notification-new-posts" in freenetRequest.parameters - val showNewReplyNotification = "show-notification-new-replies" in freenetRequest.parameters + getCurrentSone(soneRequest.toadletContext)?.options?.let { options -> + val autoFollow = "auto-follow" in soneRequest.parameters + val loadLinkedImages = soneRequest.parameters["load-linked-images"].emptyToNull + val showCustomAvatars = soneRequest.parameters["show-custom-avatars"].emptyToNull + val enableSoneInsertNotification = "enable-sone-insert-notifications" in soneRequest.parameters + val showNewSoneNotification = "show-notification-new-sones" in soneRequest.parameters + val showNewPostNotification = "show-notification-new-posts" in soneRequest.parameters + val showNewReplyNotification = "show-notification-new-replies" in soneRequest.parameters options.isAutoFollow = autoFollow options.isSoneInsertNotificationEnabled = enableSoneInsertNotification @@ -37,39 +38,39 @@ class OptionsPage(template: Template, webInterface: WebInterface): loadLinkedImages?.also { if (cantSetOption { options.loadLinkedImages = LoadExternalContent.valueOf(loadLinkedImages) }) fieldsWithErrors += "load-linked-images" } showCustomAvatars?.also { if (cantSetOption { options.showCustomAvatars = LoadExternalContent.valueOf(showCustomAvatars) }) fieldsWithErrors += "show-custom-avatars" } } - val fullAccessRequired = "require-full-access" in freenetRequest.parameters - val fcpInterfaceActive = "fcp-interface-active" in freenetRequest.parameters + val fullAccessRequired = "require-full-access" in soneRequest.parameters + val fcpInterfaceActive = "fcp-interface-active" in soneRequest.parameters - webInterface.core.preferences.isRequireFullAccess = fullAccessRequired - webInterface.core.preferences.isFcpInterfaceActive = fcpInterfaceActive + soneRequest.core.preferences.newRequireFullAccess = fullAccessRequired + soneRequest.core.preferences.newFcpInterfaceActive = fcpInterfaceActive - val postsPerPage = freenetRequest.parameters["posts-per-page"]?.toIntOrNull() - val charactersPerPost = freenetRequest.parameters["characters-per-post"]?.toIntOrNull() - val postCutOffLength = freenetRequest.parameters["post-cut-off-length"]?.toIntOrNull() - val imagesPerPage = freenetRequest.parameters["images-per-page"]?.toIntOrNull() - val insertionDelay = freenetRequest.parameters["insertion-delay"]?.toIntOrNull() - val fcpFullAccessRequired = freenetRequest.parameters["fcp-full-access-required"]?.toIntOrNull() - val negativeTrust = freenetRequest.parameters["negative-trust"]?.toIntOrNull() - val positiveTrust = freenetRequest.parameters["positive-trust"]?.toIntOrNull() - val trustComment = freenetRequest.parameters["trust-comment"]?.emptyToNull + val postsPerPage = soneRequest.parameters["posts-per-page"]?.toIntOrNull() + val charactersPerPost = soneRequest.parameters["characters-per-post"]?.toIntOrNull() + val postCutOffLength = soneRequest.parameters["post-cut-off-length"]?.toIntOrNull() + val imagesPerPage = soneRequest.parameters["images-per-page"]?.toIntOrNull() + val insertionDelay = soneRequest.parameters["insertion-delay"]?.toIntOrNull() + val fcpFullAccessRequired = soneRequest.parameters["fcp-full-access-required"]?.toIntOrNull() + val negativeTrust = soneRequest.parameters["negative-trust"]?.toIntOrNull() + val positiveTrust = soneRequest.parameters["positive-trust"]?.toIntOrNull() + val trustComment = soneRequest.parameters["trust-comment"]?.emptyToNull - if (cantSetOption { it.setPostsPerPage(postsPerPage) }) fieldsWithErrors += "posts-per-page" - if (cantSetOption { it.setCharactersPerPost(charactersPerPost) }) fieldsWithErrors += "characters-per-post" - if (cantSetOption { it.setPostCutOffLength(postCutOffLength) }) fieldsWithErrors += "post-cut-off-length" - if (cantSetOption { it.setImagesPerPage(imagesPerPage) }) fieldsWithErrors += "images-per-page" - if (cantSetOption { it.setInsertionDelay(insertionDelay) }) fieldsWithErrors += "insertion-delay" - fcpFullAccessRequired?.also { if (cantSetOption { it.fcpFullAccessRequired = FullAccessRequired.values()[fcpFullAccessRequired] }) fieldsWithErrors += "fcp-full-access-required" } - if (cantSetOption { it.setNegativeTrust(negativeTrust) }) fieldsWithErrors += "negative-trust" - if (cantSetOption { it.setPositiveTrust(positiveTrust) }) fieldsWithErrors += "positive-trust" - if (cantSetOption { it.trustComment = trustComment }) fieldsWithErrors += "trust-comment" + if (cantSetOption { soneRequest.core.preferences.newPostsPerPage = postsPerPage }) fieldsWithErrors += "posts-per-page" + if (cantSetOption { soneRequest.core.preferences.newCharactersPerPost = charactersPerPost }) fieldsWithErrors += "characters-per-post" + if (cantSetOption { soneRequest.core.preferences.newPostCutOffLength = postCutOffLength }) fieldsWithErrors += "post-cut-off-length" + if (cantSetOption { soneRequest.core.preferences.newImagesPerPage = imagesPerPage }) fieldsWithErrors += "images-per-page" + if (cantSetOption { soneRequest.core.preferences.newInsertionDelay = insertionDelay }) fieldsWithErrors += "insertion-delay" + fcpFullAccessRequired?.also { if (cantSetOption { soneRequest.core.preferences.newFcpFullAccessRequired = FullAccessRequired.values()[fcpFullAccessRequired] }) fieldsWithErrors += "fcp-full-access-required" } + if (cantSetOption { soneRequest.core.preferences.newNegativeTrust = negativeTrust }) fieldsWithErrors += "negative-trust" + if (cantSetOption { soneRequest.core.preferences.newPositiveTrust = positiveTrust }) fieldsWithErrors += "positive-trust" + if (cantSetOption { soneRequest.core.preferences.newTrustComment = trustComment }) fieldsWithErrors += "trust-comment" if (fieldsWithErrors.isEmpty()) { - webInterface.core.touchConfiguration() + soneRequest.core.touchConfiguration() throw RedirectException("options.html") } templateContext["fieldErrors"] = fieldsWithErrors } - getCurrentSone(freenetRequest.toadletContext)?.options?.let { options -> + getCurrentSone(soneRequest.toadletContext)?.options?.let { options -> templateContext["auto-follow"] = options.isAutoFollow templateContext["show-notification-new-sones"] = options.isShowNewSoneNotifications templateContext["show-notification-new-posts"] = options.isShowNewPostNotifications @@ -78,13 +79,13 @@ class OptionsPage(template: Template, webInterface: WebInterface): templateContext["load-linked-images"] = options.loadLinkedImages.toString() templateContext["show-custom-avatars"] = options.showCustomAvatars.toString() } - webInterface.core.preferences.let { preferences -> + soneRequest.core.preferences.let { preferences -> templateContext["insertion-delay"] = preferences.insertionDelay templateContext["characters-per-post"] = preferences.charactersPerPost templateContext["fcp-full-access-required"] = preferences.fcpFullAccessRequired.ordinal templateContext["images-per-page"] = preferences.imagesPerPage - templateContext["fcp-interface-active"] = preferences.isFcpInterfaceActive - templateContext["require-full-access"] = preferences.isRequireFullAccess + templateContext["fcp-interface-active"] = preferences.fcpInterfaceActive + templateContext["require-full-access"] = preferences.requireFullAccess templateContext["negative-trust"] = preferences.negativeTrust templateContext["positive-trust"] = preferences.positiveTrust templateContext["post-cut-off-length"] = preferences.postCutOffLength @@ -93,9 +94,9 @@ class OptionsPage(template: Template, webInterface: WebInterface): } } - private fun cantSetOption(setter: (Preferences) -> Unit) = + private fun cantSetOption(setter: () -> Unit) = try { - setter(webInterface.core.preferences) + setter() false } catch (iae: IllegalArgumentException) { true diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/ReloadingPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/ReloadingPage.kt index 697d173..71a7a9b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ReloadingPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ReloadingPage.kt @@ -1,14 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.util.web.Page -import net.pterodactylus.util.web.Request -import net.pterodactylus.util.web.Response -import java.io.File +import net.pterodactylus.util.web.* +import java.io.* +import javax.inject.* /** * [Page] implementation that delivers static files from the filesystem. */ -class ReloadingPage(private val prefix: String, private val path: String, private val mimeType: String): Page { +class ReloadingPage @Inject constructor(private val prefix: String, private val path: String, private val mimeType: String) : Page { override fun isPrefixPage() = true diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt index c3fabdb..2ed4940 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt @@ -1,29 +1,32 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user control the rescue mode for a Sone. */ -class RescuePage(template: Template, webInterface: WebInterface): - LoggedInPage("rescue.html", template, "Page.Rescue.Title", webInterface) { +@MenuName("Rescue") +@TemplatePath("/templates/rescue.html") +@ToadletPath("rescue.html") +class RescuePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Rescue.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - val soneRescuer = webInterface.core.getSoneRescuer(currentSone) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + val soneRescuer = soneRequest.core.getSoneRescuer(currentSone) templateContext["soneRescuer"] = soneRescuer - if (freenetRequest.isPOST) { - freenetRequest.parameters["edition", 9]?.toIntOrNull()?.also { + if (soneRequest.isPOST) { + soneRequest.parameters["edition", 9]?.toIntOrNull()?.also { if (it > -1) { soneRescuer.setEdition(it.toLong()) } } - if (freenetRequest.parameters["fetch", 8] == "true") { + if (soneRequest.parameters["fetch", 8] == "true") { soneRescuer.startNextFetch() } throw RedirectException("rescue.html") diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt index f296e03..3c14604 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt @@ -1,41 +1,38 @@ package net.pterodactylus.sone.web.pages import com.google.common.base.Ticker -import com.google.common.cache.Cache -import com.google.common.cache.CacheBuilder -import freenet.support.Logger -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.memoize -import net.pterodactylus.sone.utils.paginate -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.sone.web.pages.SearchPage.Optionality.FORBIDDEN -import net.pterodactylus.sone.web.pages.SearchPage.Optionality.OPTIONAL -import net.pterodactylus.sone.web.pages.SearchPage.Optionality.REQUIRED -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import net.pterodactylus.util.text.StringEscaper -import net.pterodactylus.util.text.TextException -import java.util.concurrent.TimeUnit.MINUTES +import com.google.common.cache.* +import freenet.support.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.sone.web.pages.SearchPage.Optionality.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.text.* +import java.util.concurrent.TimeUnit.* +import javax.inject.* /** * This page lets the user search for posts and replies that contain certain * words. */ -class SearchPage @JvmOverloads constructor(template: Template, webInterface: WebInterface, ticker: Ticker = Ticker.systemTicker()): - SoneTemplatePage("search.html", template, "Page.Search.Title", webInterface, false) { +@TemplatePath("/templates/search.html") +@ToadletPath("search.html") +class SearchPage(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer, ticker: Ticker = Ticker.systemTicker()) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Search.Title") { + + @Inject + constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + this(webInterface, loaders, templateRenderer, Ticker.systemTicker()) private val cache: Cache, Pagination> = CacheBuilder.newBuilder().ticker(ticker).expireAfterAccess(5, MINUTES).build() - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { val startTime = System.currentTimeMillis() val phrases = try { - freenetRequest.parameters["query"].emptyToNull?.parse() + soneRequest.parameters["query"].emptyToNull?.parse() } catch (te: TextException) { redirect("index.html") } @@ -45,39 +42,39 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web 0 -> redirect("index.html") 1 -> phrases.first().phrase.also { word -> when { - word.removePrefix("sone://").let(webInterface.core::getSone) != null -> redirect("viewSone.html?sone=${word.removePrefix("sone://")}") - word.removePrefix("post://").let(webInterface.core::getPost) != null -> redirect("viewPost.html?post=${word.removePrefix("post://")}") - word.removePrefix("reply://").let(webInterface.core::getPostReply) != null -> redirect("viewPost.html?post=${word.removePrefix("reply://").let(webInterface.core::getPostReply)?.postId}") - word.removePrefix("album://").let(webInterface.core::getAlbum) != null -> redirect("imageBrowser.html?album=${word.removePrefix("album://")}") - word.removePrefix("image://").let { webInterface.core.getImage(it, false) } != null -> redirect("imageBrowser.html?image=${word.removePrefix("image://")}") + word.removePrefix("sone://").let(soneRequest.core::getSone) != null -> redirect("viewSone.html?sone=${word.removePrefix("sone://")}") + word.removePrefix("post://").let(soneRequest.core::getPost) != null -> redirect("viewPost.html?post=${word.removePrefix("post://")}") + word.removePrefix("reply://").let(soneRequest.core::getPostReply) != null -> redirect("viewPost.html?post=${word.removePrefix("reply://").let(soneRequest.core::getPostReply)?.postId}") + word.removePrefix("album://").let(soneRequest.core::getAlbum) != null -> redirect("imageBrowser.html?album=${word.removePrefix("album://")}") + word.removePrefix("image://").let { soneRequest.core.getImage(it, false) } != null -> redirect("imageBrowser.html?image=${word.removePrefix("image://")}") } } } val soneNameCache = { sone: Sone -> sone.names() }.memoize() - val sonePagination = webInterface.core.sones - .scoreAndPaginate(phrases) { it.allText(soneNameCache) } - .apply { page = freenetRequest.parameters["sonePage"].emptyToNull?.toIntOrNull() ?: 0 } + val sonePagination = soneRequest.core.sones + .scoreAndPaginate(phrases, soneRequest.core.preferences.postsPerPage) { it.allText(soneNameCache) } + .apply { page = soneRequest.parameters["sonePage"].emptyToNull?.toIntOrNull() ?: 0 } val postPagination = cache.get(phrases) { - webInterface.core.sones + soneRequest.core.sones .flatMap(Sone::getPosts) .filter { Post.FUTURE_POSTS_FILTER.apply(it) } - .scoreAndPaginate(phrases) { it.allText(soneNameCache) } - }.apply { page = freenetRequest.parameters["postPage"].emptyToNull?.toIntOrNull() ?: 0 } + .scoreAndPaginate(phrases, soneRequest.core.preferences.postsPerPage) { it.allText(soneNameCache, soneRequest.core::getReplies) } + }.apply { page = soneRequest.parameters["postPage"].emptyToNull?.toIntOrNull() ?: 0 } - Logger.normal(SearchPage::class.java, "Finished search for “${freenetRequest.parameters["query"]}” in ${System.currentTimeMillis() - startTime}ms.") + Logger.normal(SearchPage::class.java, "Finished search for “${soneRequest.parameters["query"]}” in ${System.currentTimeMillis() - startTime}ms.") templateContext["sonePagination"] = sonePagination templateContext["soneHits"] = sonePagination.items templateContext["postPagination"] = postPagination templateContext["postHits"] = postPagination.items } - private fun Iterable.scoreAndPaginate(phrases: Iterable, texter: (T) -> String) = + private fun Iterable.scoreAndPaginate(phrases: Iterable, postsPerPage: Int, texter: (T) -> String) = map { it to score(texter(it), phrases) } .filter { it.second > 0 } .sortedByDescending { it.second } .map { it.first } - .paginate(webInterface.core.preferences.postsPerPage) + .paginate(postsPerPage) private fun Sone.names() = with(profile) { @@ -89,27 +86,24 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web private fun Sone.allText(soneNameCache: (Sone) -> String) = (soneNameCache(this) + profile.fields.map { "${it.name} ${it.value}" }.joinToString(" ", " ")).toLowerCase() - private fun Post.allText(soneNameCache: (Sone) -> String) = - (text + recipient.orNull()?.let { " ${soneNameCache(it)}" } + webInterface.core.getReplies(id) + private fun Post.allText(soneNameCache: (Sone) -> String, getReplies: (String) -> Collection) = + (text + recipient.orNull()?.let { " ${soneNameCache(it)}" } + getReplies(id) .filter { PostReply.FUTURE_REPLY_FILTER.apply(it) } .map { "${soneNameCache(it.sone)} ${it.text}" }.joinToString(" ", " ")).toLowerCase() + private fun Iterable.indicesFor(text: String, predicate: (Phrase) -> Boolean) = + filter(predicate).map(Phrase::phrase).map(String::toLowerCase).flatMap { text.findAll(it) } + private fun score(text: String, phrases: Iterable): Double { val requiredPhrases = phrases.count { it.required } - val requiredHits = phrases.filter(Phrase::required) - .map(Phrase::phrase) - .flatMap { text.findAll(it) } + val requiredHits = phrases.indicesFor(text, Phrase::required) .map { Math.pow(1 - it / text.length.toDouble(), 2.0) } .sum() - val optionalHits = phrases.filter(Phrase::optional) - .map(Phrase::phrase) - .flatMap { text.findAll(it) } + val optionalHits = phrases.indicesFor(text, Phrase::optional) .map { Math.pow(1 - it / text.length.toDouble(), 2.0) } .sum() - val forbiddenHits = phrases.filter(Phrase::forbidden) - .map(Phrase::phrase) - .map { text.findAll(it).size } - .sum() + val forbiddenHits = phrases.indicesFor(text, Phrase::forbidden) + .count() return requiredHits * 3 + optionalHits + (requiredHits - requiredPhrases) * 5 - (forbiddenHits * 2) } @@ -122,7 +116,6 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web private fun String.parse() = StringEscaper.parseLine(this) - .map(String::toLowerCase) .map { when { it == "+" || it == "-" -> Phrase(it, OPTIONAL) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePage.kt index 3f04236..c905ed2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePage.kt @@ -1,38 +1,30 @@ package net.pterodactylus.sone.web.pages -import freenet.clients.http.ToadletContext -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.main.SonePlugin -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.web.SessionProvider -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.sone.web.page.FreenetTemplatePage -import net.pterodactylus.util.notify.Notification -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.net.URLEncoder +import freenet.clients.http.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.notify.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.web.* +import java.net.* /** * Base page for the Sone web interface. */ open class SoneTemplatePage( - path: String, - protected val webInterface: WebInterface, - template: Template, + private val webInterface: WebInterface, + loaders: Loaders, + templateRenderer: TemplateRenderer, private val pageTitleKey: String? = null, - private val requiresLogin: Boolean = true -) : FreenetTemplatePage(path, webInterface.templateContextFactory, template, "noPermission.html") { - - @JvmOverloads - constructor(path: String, template: Template, pageTitleKey: String?, webInterface: WebInterface, requireLogin: Boolean = false) : - this(path, webInterface, template, pageTitleKey, requireLogin) - - constructor(path: String, template: Template, webInterface: WebInterface, requireLogin: Boolean = true) : - this(path, webInterface, template, null, requireLogin) + private val requiresLogin: Boolean = false, + private val pageTitle: (FreenetRequest) -> String = { pageTitleKey?.let(webInterface.l10n::getString) ?: "" } +) : FreenetTemplatePage(templateRenderer, loaders, "noPermission.html") { private val core = webInterface.core - protected val sessionProvider: SessionProvider = webInterface + private val sessionProvider: SessionProvider = webInterface protected fun getCurrentSone(toadletContext: ToadletContext, createSession: Boolean = true) = sessionProvider.getCurrentSone(toadletContext, createSession) @@ -42,15 +34,15 @@ open class SoneTemplatePage( fun requiresLogin() = requiresLogin - override public fun getPageTitle(freenetRequest: FreenetRequest) = - pageTitleKey?.let(webInterface.l10n::getString) ?: "" + override fun getPageTitle(request: FreenetRequest) = getPageTitle(request.toSoneRequest(core, webInterface)) + + open fun getPageTitle(soneRequest: SoneRequest) = pageTitle(soneRequest) - override public fun getStyleSheets() = - listOf("css/sone.css") + override val styleSheets = listOf("css/sone.css") - override public fun getShortcutIcon() = "images/icon.png" + override val shortcutIcon = "images/icon.png" - override public fun getAdditionalLinkNodes(request: FreenetRequest) = + override fun getAdditionalLinkNodes(request: FreenetRequest) = listOf(mapOf( "rel" to "search", "type" to "application/opensearchdescription+xml", @@ -58,43 +50,50 @@ open class SoneTemplatePage( "href" to "http://${request.httpRequest.getHeader("host")}/Sone/OpenSearch.xml" )) - final override public fun processTemplate(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - super.processTemplate(freenetRequest, templateContext) + final override fun processTemplate(request: FreenetRequest, templateContext: TemplateContext) { + super.processTemplate(request, templateContext) templateContext["preferences"] = core.preferences - templateContext["currentSone"] = getCurrentSone(freenetRequest.toadletContext) + templateContext["currentSone"] = getCurrentSone(request.toadletContext) templateContext["localSones"] = core.localSones - templateContext["request"] = freenetRequest + templateContext["request"] = request templateContext["currentVersion"] = SonePlugin.getPluginVersion() templateContext["hasLatestVersion"] = core.updateChecker.hasLatestVersion() templateContext["latestEdition"] = core.updateChecker.latestEdition templateContext["latestVersion"] = core.updateChecker.latestVersion templateContext["latestVersionTime"] = core.updateChecker.latestVersionDate - webInterface.getNotifications(getCurrentSone(freenetRequest.toadletContext)).sortedBy(Notification::getCreatedTime).run { + webInterface.getNotifications(getCurrentSone(request.toadletContext)).sortedBy(Notification::getCreatedTime).run { templateContext["notifications"] = this templateContext["notificationHash"] = this.hashCode() } - handleRequest(freenetRequest, templateContext) + handleRequest(request, templateContext) } - internal open fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + open fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + handleRequest(freenetRequest.toSoneRequest(core, webInterface), templateContext) } - override public fun getRedirectTarget(freenetRequest: FreenetRequest): String? { - if (requiresLogin && getCurrentSone(freenetRequest.toadletContext) == null) { - val parameters = freenetRequest.httpRequest.parameterNames - .flatMap { name -> freenetRequest.httpRequest.getMultipleParam(name).map { name to it } } + open fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + } + + override fun getRedirectTarget(request: FreenetRequest): String? { + if (requiresLogin && getCurrentSone(request.toadletContext) == null) { + val parameters = request.httpRequest.parameterNames + .flatMap { name -> request.httpRequest.getMultipleParam(name).map { name to it } } .joinToString("&") { "${it.first.urlEncode}=${it.second.urlEncode}" } .emptyToNull - return "login.html?target=${freenetRequest.httpRequest.path}${parameters?.let { ("?" + it).urlEncode } ?: ""}" + return "login.html?target=${request.httpRequest.path}${parameters?.let { ("?" + it).urlEncode } ?: ""}" } return null } private val String.urlEncode: String get() = URLEncoder.encode(this, "UTF-8") - override fun isEnabled(toadletContext: ToadletContext) = when { - requiresLogin && getCurrentSone(toadletContext) == null -> false - core.preferences.isRequireFullAccess && !toadletContext.isAllowedFullAccess -> false + override fun isEnabled(toadletContext: ToadletContext) = + isEnabled(SoneRequest(toadletContext.uri, Method.GET, HTTPRequestImpl(toadletContext.uri, "GET"), toadletContext, webInterface.l10n, webInterface.sessionManager, core, webInterface)) + + open fun isEnabled(soneRequest: SoneRequest) = when { + requiresLogin && getCurrentSone(soneRequest.toadletContext) == null -> false + core.preferences.requireFullAccess && !soneRequest.toadletContext.isAllowedFullAccess -> false else -> true } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt index 758ae07..9a4c02f 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt @@ -1,26 +1,27 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user trust another Sone. This will assign a configurable * amount of trust to an identity. */ -class TrustPage(template: Template, webInterface: WebInterface) : - LoggedInPage("trust.html", template, "Page.Trust.Title", webInterface) { +@ToadletPath("trust.html") +class TrustPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Trust.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - webInterface.core.getSone(freenetRequest.parameters["sone"]!!)?.let { sone -> - webInterface.core.trustSone(currentSone, sone) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.core.getSone(soneRequest.parameters["sone"]!!)?.let { sone -> + soneRequest.core.trustSone(currentSone, sone) } - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt index c742542..9c226d4 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt @@ -1,34 +1,33 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.utils.also -import net.pterodactylus.sone.utils.isGET -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user unbookmark a post. */ -class UnbookmarkPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("unbookmark.html", template, "Page.Unbookmark.Title", webInterface, false) { +@ToadletPath("unbookmark.html") +class UnbookmarkPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.Unbookmark.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { when { - freenetRequest.isGET && (freenetRequest.parameters["post"] == "allNotLoaded") -> { - webInterface.core.bookmarkedPosts + soneRequest.isGET && (soneRequest.parameters["post"] == "allNotLoaded") -> { + soneRequest.core.bookmarkedPosts .filterNot(Post::isLoaded) - .forEach(webInterface.core::unbookmarkPost) + .forEach(soneRequest.core::unbookmarkPost) throw RedirectException("bookmarks.html") } - freenetRequest.isPOST -> { - freenetRequest.parameters["post", 36] - ?.let(webInterface.core::getPost) - ?.also(webInterface.core::unbookmarkPost) - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + soneRequest.isPOST -> { + soneRequest.parameters["post", 36] + ?.let(soneRequest.core::getPost) + ?.also(soneRequest.core::unbookmarkPost) + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt index 2521ef0..79fdef5 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt @@ -1,24 +1,25 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user unfollow another Sone. */ -class UnfollowSonePage(template: Template, webInterface: WebInterface) : - LoggedInPage("unfollowSone.html", template, "Page.UnfollowSone.Title", webInterface) { +@ToadletPath("unfollowSone.html") +class UnfollowSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.UnfollowSone.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - freenetRequest.parameters["sone"]!!.split(Regex("[ ,]+")) - .forEach { webInterface.core.unfollowSone(currentSone, it) } - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.parameters["sone"]!!.split(Regex("[ ,]+")) + .forEach { soneRequest.core.unfollowSone(currentSone, it) } + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt index 6bfabe2..82147a9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt @@ -1,26 +1,27 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user unlike a [net.pterodactylus.sone.data.Post] or [net.pterodactylus.sone.data.Reply]. */ -class UnlikePage(template: Template, webInterface: WebInterface): - LoggedInPage("unlike.html", template, "Page.Unlike.Title", webInterface) { +@ToadletPath("unlike.html") +class UnlikePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Unlike.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - when (freenetRequest.parameters["type"]) { - "post" -> currentSone.removeLikedPostId(freenetRequest.parameters["post"]!!) - "reply" -> currentSone.removeLikedReplyId(freenetRequest.parameters["reply"]!!) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + when (soneRequest.parameters["type"]) { + "post" -> currentSone.removeLikedPostId(soneRequest.parameters["post"]!!) + "reply" -> currentSone.removeLikedReplyId(soneRequest.parameters["reply"]!!) } - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePage.kt index e792318..2c5735b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePage.kt @@ -1,24 +1,25 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * This page lets the user unlock a [net.pterodactylus.sone.data.Sone] to allow its insertion. */ -class UnlockSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("unlockSone.html", template, "Page.UnlockSone.Title", webInterface, false) { +@ToadletPath("unlockSone.html") +class UnlockSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.UnlockSone.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - freenetRequest.parameters["sone", 44] - .let(webInterface.core::getLocalSone) - ?.also(webInterface.core::unlockSone) - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.parameters["sone", 44] + .let(soneRequest.core::getLocalSone) + ?.also(soneRequest.core::unlockSone) + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt index f522c34..7dd342e 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt @@ -1,26 +1,27 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import javax.inject.* /** * Page that lets the user untrust another Sone. This will remove all trust * assignments for an identity. */ -class UntrustPage(template: Template, webInterface: WebInterface) : - LoggedInPage("untrust.html", template, "Page.Untrust.Title", webInterface) { +@ToadletPath("untrust.html") +class UntrustPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.Untrust.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - freenetRequest.parameters["sone", 44]!! - .let(webInterface.core::getSone) - ?.also { webInterface.core.untrustSone(currentSone, it) } - throw RedirectException(freenetRequest.parameters["returnPage", 256]) + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + soneRequest.parameters["sone", 44]!! + .let(soneRequest.core::getSone) + ?.also { soneRequest.core.untrustSone(currentSone, it) } + throw RedirectException(soneRequest.parameters["returnPage", 256]) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt index 4aa35ac..de61835 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt @@ -1,50 +1,48 @@ package net.pterodactylus.sone.web.pages -import freenet.support.api.Bucket -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.text.TextFilter -import net.pterodactylus.sone.utils.emptyToNull -import net.pterodactylus.sone.utils.headers -import net.pterodactylus.sone.utils.isPOST -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.utils.use -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.awt.image.BufferedImage -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import javax.imageio.ImageIO +import freenet.support.api.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import java.awt.image.* +import java.io.* +import javax.imageio.* +import javax.inject.* /** * Page implementation that lets the user upload an image. */ -class UploadImagePage(template: Template, webInterface: WebInterface): - LoggedInPage("uploadImage.html", template, "Page.UploadImage.Title", webInterface) { +@TemplatePath("/templates/invalid.html") +@ToadletPath("uploadImage.html") +class UploadImagePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + LoggedInPage("Page.UploadImage.Title", webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { - if (freenetRequest.isPOST) { - val parentAlbum = freenetRequest.parameters["parent"]!!.let(webInterface.core::getAlbum) ?: throw RedirectException("noPermission.html") + override fun handleRequest(soneRequest: SoneRequest, currentSone: Sone, templateContext: TemplateContext) { + if (soneRequest.isPOST) { + val parentAlbum = soneRequest.parameters["parent"]!!.let(soneRequest.core::getAlbum) ?: throw RedirectException("noPermission.html") if (parentAlbum.sone != currentSone) { throw RedirectException("noPermission.html") } - val title = freenetRequest.parameters["title", 200].emptyToNull ?: throw RedirectException("emptyImageTitle.html") + val title = soneRequest.parameters["title", 200].emptyToNull ?: throw RedirectException("emptyImageTitle.html") - val uploadedFile = freenetRequest.httpRequest.getUploadedFile("image") + val uploadedFile = soneRequest.httpRequest.getUploadedFile("image") val bytes = uploadedFile.data.use { it.toByteArray() } val bufferedImage = bytes.toImage() if (bufferedImage == null) { - templateContext["messages"] = webInterface.l10n.getString("Page.UploadImage.Error.InvalidImage") + templateContext["messages"] = soneRequest.l10n.getString("Page.UploadImage.Error.InvalidImage") return } - val temporaryImage = webInterface.core.createTemporaryImage(bytes.mimeType, bytes) - webInterface.core.createImage(currentSone, parentAlbum, temporaryImage).modify().apply { + val temporaryImage = soneRequest.core.createTemporaryImage(bytes.mimeType, bytes) + soneRequest.core.createImage(currentSone, parentAlbum, temporaryImage).modify().apply { setWidth(bufferedImage.width) setHeight(bufferedImage.height) setTitle(title) - setDescription(TextFilter.filter(freenetRequest.headers["Host"], freenetRequest.parameters["description", 4000])) + setDescription(TextFilter.filter(soneRequest.headers["Host"], soneRequest.parameters["description", 4000])) }.update() throw RedirectException("imageBrowser.html?album=${parentAlbum.id}") } @@ -59,13 +57,14 @@ class UploadImagePage(template: Template, webInterface: WebInterface): ImageIO.read(it) } - private val ByteArray.mimeType get() = ByteArrayInputStream(this).use { - ImageIO.createImageInputStream(it).use { - ImageIO.getImageReaders(it).asSequence() - .firstOrNull()?.originatingProvider?.mimeTypes?.firstOrNull() - ?: UNKNOWN_MIME_TYPE + private val ByteArray.mimeType + get() = ByteArrayInputStream(this).use { + ImageIO.createImageInputStream(it).use { + ImageIO.getImageReaders(it).asSequence() + .firstOrNull()?.originatingProvider?.mimeTypes?.firstOrNull() + ?: UNKNOWN_MIME_TYPE + } } - } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt index 910c939..7e4d6a5 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt @@ -1,34 +1,36 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.template.SoneAccessor -import net.pterodactylus.sone.utils.let -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.net.URI +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.template.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import java.net.* +import javax.inject.* /** * This page lets the user view a post and all its replies. */ -class ViewPostPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("viewPost.html", template, "Page.ViewPost.Title", webInterface, false) { +@TemplatePath("/templates/viewPost.html") +@ToadletPath("viewPost.html") +class ViewPostPage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "Page.ViewPost.Title") { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - templateContext["post"] = freenetRequest.parameters["post"]?.let(webInterface.core::getPost) - templateContext["raw"] = freenetRequest.parameters["raw"] == "true" + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + templateContext["post"] = soneRequest.parameters["post"]?.let(soneRequest.core::getPost) + templateContext["raw"] = soneRequest.parameters["raw"] == "true" } - override fun isLinkExcepted(link: URI?) = true + override fun isLinkExcepted(link: URI) = true - public override fun getPageTitle(freenetRequest: FreenetRequest) = - (freenetRequest.parameters["post"]?.let(webInterface.core::getPost)?.let { + override fun getPageTitle(soneRequest: SoneRequest) = + (soneRequest.parameters["post"]?.let(soneRequest.core::getPost)?.let { if (it.text.length > 20) { it.text.substring(0..19) + "…" } else { it.text } + " - ${SoneAccessor.getNiceName(it.sone)} - " - } ?: "") + super.getPageTitle(freenetRequest) + } ?: "") + super.getPageTitle(soneRequest) } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt index 2e175af..a498d24 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt @@ -1,33 +1,33 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.template.SoneAccessor -import net.pterodactylus.sone.utils.mapPresent -import net.pterodactylus.sone.utils.paginate -import net.pterodactylus.sone.utils.parameters -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import java.net.URI +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.template.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import java.net.* +import javax.inject.* /** * Lets the user browser another Sone. */ -class ViewSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("viewSone.html", template, webInterface, false) { +@TemplatePath("/templates/viewSone.html") +@ToadletPath("viewSone.html") +class ViewSonePage @Inject constructor(webInterface: WebInterface, loaders: Loaders, templateRenderer: TemplateRenderer) : + SoneTemplatePage(webInterface, loaders, templateRenderer) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - templateContext["soneId"] = freenetRequest.parameters["sone"] - freenetRequest.parameters["sone"]!!.let(webInterface.core::getSone)?.let { sone -> + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + templateContext["soneId"] = soneRequest.parameters["sone"] + soneRequest.parameters["sone"]!!.let(soneRequest.core::getSone)?.let { sone -> templateContext["sone"] = sone val sonePosts = sone.posts - val directedPosts = webInterface.core.getDirectedPosts(sone.id) + val directedPosts = soneRequest.core.getDirectedPosts(sone.id) (sonePosts + directedPosts) .sortedByDescending(Post::getTime) - .paginate(webInterface.core.preferences.postsPerPage) - .apply { page = freenetRequest.parameters["postPage"]?.toIntOrNull() ?: 0 } + .paginate(soneRequest.core.preferences.postsPerPage) + .apply { page = soneRequest.parameters["postPage"]?.toIntOrNull() ?: 0 } .also { templateContext["postPagination"] = it templateContext["posts"] = it.items @@ -37,9 +37,9 @@ class ViewSonePage(template: Template, webInterface: WebInterface): .distinct() .minus(sonePosts) .minus(directedPosts) - .sortedByDescending { webInterface.core.getReplies(it.id).first().time } - .paginate(webInterface.core.preferences.postsPerPage) - .apply { page = freenetRequest.parameters["repliedPostPage"]?.toIntOrNull() ?: 0 } + .sortedByDescending { soneRequest.core.getReplies(it.id).first().time } + .paginate(soneRequest.core.preferences.postsPerPage) + .apply { page = soneRequest.parameters["repliedPostPage"]?.toIntOrNull() ?: 0 } .also { templateContext["repliedPostPagination"] = it templateContext["repliedPosts"] = it.items @@ -47,11 +47,11 @@ class ViewSonePage(template: Template, webInterface: WebInterface): } } - override fun isLinkExcepted(link: URI?) = true + override fun isLinkExcepted(link: URI) = true - public override fun getPageTitle(freenetRequest: FreenetRequest): String = - freenetRequest.parameters["sone"]!!.let(webInterface.core::getSone)?.let { sone -> - "${SoneAccessor.getNiceName(sone)} - ${webInterface.l10n.getString("Page.ViewSone.Title")}" - } ?: webInterface.l10n.getString("Page.ViewSone.Page.TitleWithoutSone") + override fun getPageTitle(soneRequest: SoneRequest): String = + soneRequest.parameters["sone"]!!.let(soneRequest.core::getSone)?.let { sone -> + "${SoneAccessor.getNiceName(sone)} - ${soneRequest.l10n.getString("Page.ViewSone.Title")}" + } ?: soneRequest.l10n.getString("Page.ViewSone.Page.TitleWithoutSone") } diff --git a/src/main/resources/i18n/sone.de.properties b/src/main/resources/i18n/sone.de.properties index e655691..7e42167 100644 --- a/src/main/resources/i18n/sone.de.properties +++ b/src/main/resources/i18n/sone.de.properties @@ -227,7 +227,7 @@ Page.FollowSone.Title=Sone folgen - Sone Page.UnfollowSone.Title=Sone entfolgen - Sone -Page.ImageBrowser.Title=Bildergallerie - Sone +Page.ImageBrowser.Title=Bildergalerie - Sone Page.ImageBrowser.Album.Title=Album “{album}” Page.ImageBrowser.Album.Error.NotFound.Text=Das gewünschte Album konnte nicht gefunden werden. Es ist möglich, dass es noch nicht herunter geladen oder bereits gelöscht wurde. Page.ImageBrowser.Sone.Title=Alben von {sone} diff --git a/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java index 4a26203..4edc1b7 100644 --- a/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java +++ b/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java @@ -57,8 +57,6 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link ConfigurationSoneParser}. - * - * @author David ‘Bombe’ Roden */ public class ConfigurationSoneParserTest { diff --git a/src/test/java/net/pterodactylus/sone/core/CoreTest.java b/src/test/java/net/pterodactylus/sone/core/CoreTest.java index dbe70d5..66ef743 100644 --- a/src/test/java/net/pterodactylus/sone/core/CoreTest.java +++ b/src/test/java/net/pterodactylus/sone/core/CoreTest.java @@ -33,8 +33,6 @@ import org.mockito.InOrder; /** * Unit test for {@link Core} and its subclasses. - * - * @author David ‘Bombe’ Roden */ public class CoreTest { diff --git a/src/test/java/net/pterodactylus/sone/core/FreenetInterfaceTest.java b/src/test/java/net/pterodactylus/sone/core/FreenetInterfaceTest.java index 2ebc428..c91de68 100644 --- a/src/test/java/net/pterodactylus/sone/core/FreenetInterfaceTest.java +++ b/src/test/java/net/pterodactylus/sone/core/FreenetInterfaceTest.java @@ -31,7 +31,6 @@ import java.util.HashMap; import net.pterodactylus.sone.core.FreenetInterface.BackgroundFetchCallback; import net.pterodactylus.sone.core.FreenetInterface.Callback; -import net.pterodactylus.sone.core.FreenetInterface.Fetched; import net.pterodactylus.sone.core.FreenetInterface.InsertToken; import net.pterodactylus.sone.core.FreenetInterface.InsertTokenSupplier; import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent; @@ -83,8 +82,6 @@ import org.mockito.ArgumentMatchers; /** * Unit test for {@link FreenetInterface}. - * - * @author David ‘Bombe’ Roden */ public class FreenetInterfaceTest { @@ -215,7 +212,7 @@ public class FreenetInterfaceTest { @Test public void insertingADirectory() throws InsertException, SoneException { FreenetURI freenetUri = mock(FreenetURI.class); - HashMap manifestEntries = new HashMap(); + HashMap manifestEntries = new HashMap<>(); String defaultFile = "index.html"; FreenetURI resultingUri = mock(FreenetURI.class); when(highLevelSimpleClient.insertManifest(eq(freenetUri), eq(manifestEntries), eq(defaultFile))).thenReturn(resultingUri); @@ -240,7 +237,7 @@ public class FreenetInterfaceTest { FreenetURI freenetUri = createRandom(randomSource, "test-0").getURI().uskForSSK(); Callback callback = mock(Callback.class); freenetInterface.registerUsk(freenetUri, callback); - verify(uskManager).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), eq((RequestClient) highLevelSimpleClient)); + verify(uskManager).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), any(RequestClient.class)); } @Test @@ -248,7 +245,7 @@ public class FreenetInterfaceTest { FreenetURI freenetUri = new FreenetURI("KSK@GPLv3.txt"); Callback callback = mock(Callback.class); freenetInterface.registerUsk(freenetUri, callback); - verify(uskManager, never()).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), eq((RequestClient) highLevelSimpleClient)); + verify(uskManager, never()).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), any(RequestClient.class)); } @Test @@ -272,9 +269,7 @@ public class FreenetInterfaceTest { throws MalformedURLException { FreenetURI freenetUri = createRandom(randomSource, "test-0").getURI(); freenetInterface.registerActiveUsk(freenetUri, null); - verify(uskManager, never()).subscribe(any(USK.class), - any(USKCallback.class), anyBoolean(), - eq((RequestClient) highLevelSimpleClient)); + verify(uskManager, never()).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), any(RequestClient.class)); } @Test @@ -282,9 +277,7 @@ public class FreenetInterfaceTest { throws MalformedURLException { FreenetURI freenetUri = createRandom(randomSource, "test-0").getURI(); freenetInterface.registerPassiveUsk(freenetUri, null); - verify(uskManager, never()).subscribe(any(USK.class), - any(USKCallback.class), anyBoolean(), - eq((RequestClient) highLevelSimpleClient)); + verify(uskManager, never()).subscribe(any(USK.class), any(USKCallback.class), anyBoolean(), any(RequestClient.class)); } @Test @@ -420,7 +413,7 @@ public class FreenetInterfaceTest { @Test public void insertTokenSupplierSuppliesInsertTokens() { - InsertTokenSupplier insertTokenSupplier = freenetInterface.new InsertTokenSupplier(); + InsertTokenSupplier insertTokenSupplier = new InsertTokenSupplier(freenetInterface); assertThat(insertTokenSupplier.apply(image), notNullValue()); } diff --git a/src/test/java/net/pterodactylus/sone/core/ImageInserterTest.java b/src/test/java/net/pterodactylus/sone/core/ImageInserterTest.java deleted file mode 100644 index 75788d1..0000000 --- a/src/test/java/net/pterodactylus/sone/core/ImageInserterTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.pterodactylus.sone.core; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import net.pterodactylus.sone.core.FreenetInterface.InsertToken; -import net.pterodactylus.sone.data.Image; -import net.pterodactylus.sone.data.TemporaryImage; - -import com.google.common.base.Function; -import org.junit.Test; - -/** - * Unit test for {@link ImageInserter}. - * - * @author David ‘Bombe’ Roden - */ -public class ImageInserterTest { - - private final TemporaryImage temporaryImage = when(mock(TemporaryImage.class).getId()).thenReturn("image-id").getMock(); - private final Image image = when(mock(Image.class).getId()).thenReturn("image-id").getMock(); - private final FreenetInterface freenetInterface = mock(FreenetInterface.class); - private final InsertToken insertToken = mock(InsertToken.class); - private final Function insertTokenSupplier = when(mock(Function.class).apply(any(Image.class))).thenReturn(insertToken).getMock(); - private final ImageInserter imageInserter = new ImageInserter(freenetInterface, insertTokenSupplier); - - @Test - public void inserterInsertsImage() throws SoneException { - imageInserter.insertImage(temporaryImage, image); - verify(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken.class)); - } - - @Test - public void exceptionWhenInsertingImageIsIgnored() throws SoneException { - doThrow(SoneException.class).when(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken.class)); - imageInserter.insertImage(temporaryImage, image); - verify(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken.class)); - } - - @Test - public void cancellingImageInsertThatIsNotRunningDoesNothing() { - imageInserter.cancelImageInsert(image); - verify(insertToken, never()).cancel(); - } - - @Test - public void cancellingImage() { - imageInserter.insertImage(temporaryImage, image); - imageInserter.cancelImageInsert(image); - verify(insertToken).cancel(); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/core/OptionsTest.java b/src/test/java/net/pterodactylus/sone/core/OptionsTest.java index cce4df0..113430c 100644 --- a/src/test/java/net/pterodactylus/sone/core/OptionsTest.java +++ b/src/test/java/net/pterodactylus/sone/core/OptionsTest.java @@ -11,8 +11,6 @@ import org.junit.Test; /** * Unit test for {@link Options}. - * - * @author David ‘Bombe’ Roden */ public class OptionsTest { diff --git a/src/test/java/net/pterodactylus/sone/core/PreferencesLoaderTest.java b/src/test/java/net/pterodactylus/sone/core/PreferencesLoaderTest.java index 49777f0..d550f25 100644 --- a/src/test/java/net/pterodactylus/sone/core/PreferencesLoaderTest.java +++ b/src/test/java/net/pterodactylus/sone/core/PreferencesLoaderTest.java @@ -16,8 +16,6 @@ import org.junit.Test; /** * Unit test for {@link PreferencesLoader}. - * - * @author David ‘Bombe’ Roden */ public class PreferencesLoaderTest { @@ -63,11 +61,11 @@ public class PreferencesLoaderTest { assertThat(preferences.getImagesPerPage(), is(12)); assertThat(preferences.getCharactersPerPost(), is(150)); assertThat(preferences.getPostCutOffLength(), is(300)); - assertThat(preferences.isRequireFullAccess(), is(true)); + assertThat(preferences.getRequireFullAccess(), is(true)); assertThat(preferences.getPositiveTrust(), is(50)); assertThat(preferences.getNegativeTrust(), is(-50)); assertThat(preferences.getTrustComment(), is("Trusted")); - assertThat(preferences.isFcpInterfaceActive(), is(true)); + assertThat(preferences.getFcpInterfaceActive(), is(true)); assertThat(preferences.getFcpFullAccessRequired(), is(WRITING)); } diff --git a/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java b/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java deleted file mode 100644 index 6756185..0000000 --- a/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java +++ /dev/null @@ -1,311 +0,0 @@ -package net.pterodactylus.sone.core; - -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS; -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO; -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; -import net.pterodactylus.sone.fcp.event.FcpInterfaceActivatedEvent; -import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent; -import net.pterodactylus.sone.fcp.event.FullAccessRequiredChanged; - -import com.google.common.eventbus.EventBus; -import org.junit.After; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -/** - * Unit test for {@link Preferences}. - * - * @author David ‘Bombe’ Roden - */ -public class PreferencesTest { - - private final EventBus eventBus = mock(EventBus.class); - private final Preferences preferences = new Preferences(eventBus); - - @After - public void tearDown() { - verifyNoMoreInteractions(eventBus); - } - - @Test - public void preferencesRetainInsertionDelay() { - preferences.setInsertionDelay(15); - assertThat(preferences.getInsertionDelay(), is(15)); - verify(eventBus).post(any(InsertionDelayChangedEvent.class)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidInsertionDelayIsRejected() { - preferences.setInsertionDelay(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenInsertionDelayIsSetToNull() { - preferences.setInsertionDelay(null); - assertThat(preferences.getInsertionDelay(), is(60)); - verify(eventBus).post(any(InsertionDelayChangedEvent.class)); - } - - @Test - public void preferencesStartWithInsertionDelayDefaultValue() { - assertThat(preferences.getInsertionDelay(), is(60)); - } - - @Test - public void preferencesRetainPostsPerPage() { - preferences.setPostsPerPage(15); - assertThat(preferences.getPostsPerPage(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPostsPerPageIsRejected() { - preferences.setPostsPerPage(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenPostsPerPageIsSetToNull() { - preferences.setPostsPerPage(null); - assertThat(preferences.getPostsPerPage(), is(10)); - } - - @Test - public void preferencesStartWithPostsPerPageDefaultValue() { - assertThat(preferences.getPostsPerPage(), is(10)); - } - - @Test - public void preferencesRetainImagesPerPage() { - preferences.setImagesPerPage(15); - assertThat(preferences.getImagesPerPage(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidImagesPerPageIsRejected() { - preferences.setImagesPerPage(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenImagesPerPageIsSetToNull() { - preferences.setImagesPerPage(null); - assertThat(preferences.getImagesPerPage(), is(9)); - } - - @Test - public void preferencesStartWithImagesPerPageDefaultValue() { - assertThat(preferences.getImagesPerPage(), is(9)); - } - - @Test - public void preferencesRetainCharactersPerPost() { - preferences.setCharactersPerPost(150); - assertThat(preferences.getCharactersPerPost(), is(150)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidCharactersPerPostIsRejected() { - preferences.setCharactersPerPost(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenCharactersPerPostIsSetToNull() { - preferences.setCharactersPerPost(null); - assertThat(preferences.getCharactersPerPost(), is(400)); - } - - @Test - public void preferencesStartWithCharactersPerPostDefaultValue() { - assertThat(preferences.getCharactersPerPost(), is(400)); - } - - @Test - public void preferencesRetainPostCutOffLength() { - preferences.setPostCutOffLength(150); - assertThat(preferences.getPostCutOffLength(), is(150)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPostCutOffLengthIsRejected() { - preferences.setPostCutOffLength(-15); - } - - @Test(expected = IllegalArgumentException.class) - public void cutOffLengthOfMinusOneIsNotAllowed() { - preferences.setPostCutOffLength(-1); - } - - @Test - public void preferencesReturnDefaultValueWhenPostCutOffLengthIsSetToNull() { - preferences.setPostCutOffLength(null); - assertThat(preferences.getPostCutOffLength(), is(200)); - } - - @Test - public void preferencesStartWithPostCutOffLengthDefaultValue() { - assertThat(preferences.getPostCutOffLength(), is(200)); - } - - @Test - public void preferencesRetainRequireFullAccessOfTrue() { - preferences.setRequireFullAccess(true); - assertThat(preferences.isRequireFullAccess(), is(true)); - } - - @Test - public void preferencesRetainRequireFullAccessOfFalse() { - preferences.setRequireFullAccess(false); - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesReturnDefaultValueWhenRequireFullAccessIsSetToNull() { - preferences.setRequireFullAccess(null); - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesStartWithRequireFullAccessDefaultValue() { - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesRetainPositiveTrust() { - preferences.setPositiveTrust(15); - assertThat(preferences.getPositiveTrust(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPositiveTrustIsRejected() { - preferences.setPositiveTrust(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenPositiveTrustIsSetToNull() { - preferences.setPositiveTrust(null); - assertThat(preferences.getPositiveTrust(), is(75)); - } - - @Test - public void preferencesStartWithPositiveTrustDefaultValue() { - assertThat(preferences.getPositiveTrust(), is(75)); - } - - @Test - public void preferencesRetainNegativeTrust() { - preferences.setNegativeTrust(-15); - assertThat(preferences.getNegativeTrust(), is(-15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidNegativeTrustIsRejected() { - preferences.setNegativeTrust(150); - } - - @Test - public void preferencesReturnDefaultValueWhenNegativeTrustIsSetToNull() { - preferences.setNegativeTrust(null); - assertThat(preferences.getNegativeTrust(), is(-25)); - } - - @Test - public void preferencesStartWithNegativeTrustDefaultValue() { - assertThat(preferences.getNegativeTrust(), is(-25)); - } - - @Test - public void preferencesRetainTrustComment() { - preferences.setTrustComment("Trust"); - assertThat(preferences.getTrustComment(), is("Trust")); - } - - @Test - public void preferencesReturnDefaultValueWhenTrustCommentIsSetToNull() { - preferences.setTrustComment(null); - assertThat(preferences.getTrustComment(), - is("Set from Sone Web Interface")); - } - - @Test - public void preferencesStartWithTrustCommentDefaultValue() { - assertThat(preferences.getTrustComment(), - is("Set from Sone Web Interface")); - } - - @Test - public void preferencesRetainFcpInterfaceActiveOfTrue() { - preferences.setFcpInterfaceActive(true); - assertThat(preferences.isFcpInterfaceActive(), is(true)); - verify(eventBus).post(any(FcpInterfaceActivatedEvent.class)); - } - - @Test - public void preferencesRetainFcpInterfaceActiveOfFalse() { - preferences.setFcpInterfaceActive(false); - assertThat(preferences.isFcpInterfaceActive(), is(false)); - verify(eventBus).post(any(FcpInterfaceDeactivatedEvent.class)); - } - - @Test - public void preferencesReturnDefaultValueWhenFcpInterfaceActiveIsSetToNull() { - preferences.setFcpInterfaceActive(null); - assertThat(preferences.isFcpInterfaceActive(), is(false)); - verify(eventBus).post(any(FcpInterfaceDeactivatedEvent.class)); - } - - @Test - public void preferencesStartWithFcpInterfaceActiveDefaultValue() { - assertThat(preferences.isFcpInterfaceActive(), is(false)); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfNo() { - preferences.setFcpFullAccessRequired(NO); - assertThat(preferences.getFcpFullAccessRequired(), is(NO)); - verifyFullAccessRequiredChangedEvent(NO); - } - - private void verifyFullAccessRequiredChangedEvent( - FullAccessRequired fullAccessRequired) { - ArgumentCaptor fullAccessRequiredCaptor = - ArgumentCaptor.forClass(FullAccessRequiredChanged.class); - verify(eventBus).post(fullAccessRequiredCaptor.capture()); - assertThat( - fullAccessRequiredCaptor.getValue().getFullAccessRequired(), - is(fullAccessRequired)); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfWriting() { - preferences.setFcpFullAccessRequired(WRITING); - assertThat(preferences.getFcpFullAccessRequired(), is(WRITING)); - verifyFullAccessRequiredChangedEvent(WRITING); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfAlways() { - preferences.setFcpFullAccessRequired(ALWAYS); - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - verifyFullAccessRequiredChangedEvent(ALWAYS); - } - - @Test - public void preferencesReturnDefaultValueWhenFcpFullAccessRequiredIsSetToNull() { - preferences.setFcpFullAccessRequired(null); - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - verifyFullAccessRequiredChangedEvent(ALWAYS); - } - - @Test - public void preferencesStartWithFcpFullAccessRequiredDefaultValue() { - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java b/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java deleted file mode 100644 index 34e3573..0000000 --- a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java +++ /dev/null @@ -1,108 +0,0 @@ -package net.pterodactylus.sone.core; - -import static java.util.Arrays.asList; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashSet; - -import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link SoneChangeDetector}. - * - * @author David ‘Bombe’ Roden - */ -public class SoneChangeDetectorTest { - - private final Sone oldSone = mock(Sone.class); - private final Sone newSone = mock(Sone.class); - private final SoneChangeDetector soneChangeDetector = - new SoneChangeDetector(oldSone); - private final Post oldPost = mock(Post.class); - private final Post removedPost = mock(Post.class); - private final Post newPost = mock(Post.class); - private final PostProcessor newPostProcessor = mock(PostProcessor.class); - private final PostProcessor removedPostProcessor = - mock(PostProcessor.class); - private final PostReply oldPostReply = mock(PostReply.class); - private final PostReply removedPostReply = mock(PostReply.class); - private final PostReply newPostReply = mock(PostReply.class); - private final PostReplyProcessor newPostReplyProcessor = - mock(PostReplyProcessor.class); - private final PostReplyProcessor removedPostReplyProcessor = - mock(PostReplyProcessor.class); - - @Before - public void setupPosts() { - when(oldSone.getPosts()).thenReturn(asList(oldPost, removedPost)); - when(newSone.getPosts()).thenReturn(asList(oldPost, newPost)); - } - - @Before - public void setupPostProcessors() { - soneChangeDetector.onNewPosts(newPostProcessor); - soneChangeDetector.onRemovedPosts(removedPostProcessor); - } - - @Before - public void setupPostReplies() { - when(oldSone.getReplies()).thenReturn( - new HashSet( - asList(oldPostReply, removedPostReply))); - when(newSone.getReplies()).thenReturn( - new HashSet(asList(oldPostReply, newPostReply))); - } - - @Before - public void setupPostReplyProcessors() { - soneChangeDetector.onNewPostReplies(newPostReplyProcessor); - soneChangeDetector.onRemovedPostReplies(removedPostReplyProcessor); - } - - @Test - public void changeDetectorDetectsChanges() { - soneChangeDetector.detectChanges(newSone); - - verify(newPostProcessor).processPost(newPost); - verify(newPostProcessor, never()).processPost(oldPost); - verify(newPostProcessor, never()).processPost(removedPost); - verify(removedPostProcessor).processPost(removedPost); - verify(removedPostProcessor, never()).processPost(oldPost); - verify(removedPostProcessor, never()).processPost(newPost); - - verify(newPostReplyProcessor).processPostReply(newPostReply); - verify(newPostReplyProcessor, never()).processPostReply(oldPostReply); - verify(newPostReplyProcessor, never()).processPostReply( - removedPostReply); - verify(removedPostReplyProcessor).processPostReply(removedPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - oldPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - newPostReply); - } - - @Test - public void changeDetectorDoesNotNotifyAnyProcessorIfProcessorsUnset() { - soneChangeDetector.onNewPosts(null); - soneChangeDetector.onRemovedPosts(null); - soneChangeDetector.onNewPostReplies(null); - soneChangeDetector.onRemovedPostReplies(null); - soneChangeDetector.detectChanges(newSone); - verify(newPostProcessor, never()).processPost(any(Post.class)); - verify(removedPostProcessor, never()).processPost(any(Post.class)); - verify(newPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - verify(removedPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/core/SoneDownloaderTest.java b/src/test/java/net/pterodactylus/sone/core/SoneDownloaderTest.java index 9043974..284d9b2 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneDownloaderTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneDownloaderTest.java @@ -6,8 +6,10 @@ import static java.util.concurrent.TimeUnit.DAYS; import static net.pterodactylus.sone.data.Sone.SoneStatus.downloading; import static net.pterodactylus.sone.data.Sone.SoneStatus.idle; import static net.pterodactylus.sone.data.Sone.SoneStatus.unknown; +import static net.pterodactylus.sone.web.AllPagesTestKt.getBaseInjector; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.mockito.ArgumentCaptor.forClass; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -20,10 +22,10 @@ import static org.mockito.Mockito.when; import java.io.IOException; import java.io.InputStream; -import net.pterodactylus.sone.core.FreenetInterface.Fetched; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.data.Sone.SoneStatus; import net.pterodactylus.sone.freenet.wot.Identity; +import net.pterodactylus.sone.test.GuiceKt; import freenet.client.ClientMetadata; import freenet.client.FetchResult; @@ -36,40 +38,30 @@ import freenet.support.api.Bucket; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; /** * Unit test for {@link SoneDownloaderImpl} and its subclasses. - * - * @author David ‘Bombe’ Roden */ public class SoneDownloaderTest { - private final Core core = mock(Core.class); private final FreenetInterface freenetInterface = mock(FreenetInterface.class); private final SoneParser soneParser = mock(SoneParser.class); - private final SoneDownloaderImpl soneDownloader = new SoneDownloaderImpl(core, freenetInterface, soneParser); - private FreenetURI requestUri = mock(FreenetURI.class); - private Sone sone = mock(Sone.class); + private final UpdatedSoneProcessor updatedSoneProcessor = mock(UpdatedSoneProcessor.class); + private final SoneDownloaderImpl soneDownloader = new SoneDownloaderImpl(updatedSoneProcessor, freenetInterface, soneParser); + private final InsertableClientSSK clientSSK = createRandom(new DummyRandomSource(), "WoT"); + private final FreenetURI requestUri = clientSSK.getURI().setKeyType("USK").setDocName("Sone"); + private final FreenetURI finalRequestUri = requestUri.setMetaString(new String[] { "sone.xml" }); + private final Sone sone = mock(Sone.class); + private final Sone parsedSone = mock(Sone.class); @Before public void setupSone() { - Sone sone = SoneDownloaderTest.this.sone; Identity identity = mock(Identity.class); - InsertableClientSSK clientSSK = createRandom(new DummyRandomSource(), "WoT"); when(identity.getRequestUri()).thenReturn(clientSSK.getURI().toString()); when(identity.getId()).thenReturn("identity"); when(sone.getId()).thenReturn("identity"); when(sone.getIdentity()).thenReturn(identity); - requestUri = clientSSK.getURI().setKeyType("USK").setDocName("Sone"); - when(sone.getRequestUri()).thenAnswer(new Answer() { - @Override - public FreenetURI answer(InvocationOnMock invocation) - throws Throwable { - return requestUri; - } - }); + when(sone.getRequestUri()).thenReturn(requestUri); when(sone.getTime()).thenReturn(currentTimeMillis() - DAYS.toMillis(1)); } @@ -104,13 +96,11 @@ public class SoneDownloaderTest { @Test public void notBeingAbleToFetchAnUnknownSoneDoesNotUpdateCore() { - FreenetURI finalRequestUri = requestUri.sskForUSK() - .setMetaString(new String[] { "sone.xml" }); setupSoneAsUnknown(); - soneDownloader.fetchSoneAction(sone).run(); - verify(freenetInterface).fetchUri(finalRequestUri); + soneDownloader.fetchSoneAsSskAction(sone).run(); + verify(freenetInterface).fetchUri(finalRequestUri.sskForUSK()); verifyThatSoneStatusWasChangedToDownloadingAndBackTo(unknown); - verify(core, never()).updateSone(any(Sone.class)); + verify(updatedSoneProcessor, never()).updateSone(any(Sone.class)); } private void verifyThatSoneStatusWasChangedToDownloadingAndBackTo(SoneStatus soneStatus) { @@ -122,75 +112,55 @@ public class SoneDownloaderTest { @Test public void notBeingAbleToFetchAKnownSoneDoesNotUpdateCore() { - FreenetURI finalRequestUri = requestUri.sskForUSK() - .setMetaString(new String[] { "sone.xml" }); - soneDownloader.fetchSoneAction(sone).run(); - verify(freenetInterface).fetchUri(finalRequestUri); + soneDownloader.fetchSoneAsSskAction(sone).run(); + verify(freenetInterface).fetchUri(finalRequestUri.sskForUSK()); verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle); - verify(core, never()).updateSone(any(Sone.class)); + verify(updatedSoneProcessor, never()).updateSone(any(Sone.class)); } @Test(expected = NullPointerException.class) - public void exceptionWhileFetchingAnUnknownSoneDoesNotUpdateCore() { - FreenetURI finalRequestUri = requestUri.sskForUSK() - .setMetaString(new String[] { "sone.xml" }); - setupSoneAsUnknown(); - when(freenetInterface.fetchUri(finalRequestUri)).thenThrow(NullPointerException.class); - try { - soneDownloader.fetchSoneAction(sone).run(); - } finally { - verify(freenetInterface).fetchUri(finalRequestUri); - verifyThatSoneStatusWasChangedToDownloadingAndBackTo(unknown); - verify(core, never()).updateSone(any(Sone.class)); - } - } - - @Test(expected = NullPointerException.class) - public void exceptionWhileFetchingAKnownSoneDoesNotUpdateCore() { - FreenetURI finalRequestUri = requestUri.sskForUSK() - .setMetaString(new String[] { "sone.xml" }); - when(freenetInterface.fetchUri(finalRequestUri)).thenThrow( NullPointerException.class); + public void exceptionWhileFetchingSoneDoesNotProcessUpdatedSone() { + when(freenetInterface.fetchUri(any(FreenetURI.class))).thenThrow(NullPointerException.class); try { - soneDownloader.fetchSoneAction(sone).run(); + soneDownloader.fetchSoneAsSskAction(sone).run(); } finally { - verify(freenetInterface).fetchUri(finalRequestUri); - verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle); - verify(core, never()).updateSone(any(Sone.class)); + verify(updatedSoneProcessor, never()).updateSone(any(Sone.class)); } } @Test - public void fetchingSoneWithInvalidXmlWillNotUpdateTheCore() throws IOException { - final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-not-xml.xml")); - when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult); - soneDownloader.fetchSoneAction(sone).run(); - verify(core, never()).updateSone(any(Sone.class)); - } - - @Test - public void exceptionWhileFetchingSoneWillNotUpdateTheCore() throws IOException { - final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-no-payload.xml")); - when(core.soneBuilder()).thenReturn(null); - when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult); - soneDownloader.fetchSoneAction(sone).run(); - verify(core, never()).updateSone(any(Sone.class)); + public void onlyFetchingASoneWillNotUpdateTheCore() throws IOException, SoneException { + setupParsedSone(); + soneDownloader.fetchSone(sone, sone.getRequestUri(), true); + verify(updatedSoneProcessor, never()).updateSone(any(Sone.class)); + verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle); } @Test - public void onlyFetchingASoneWillNotUpdateTheCore() throws IOException { - final Fetched fetchResult = createFetchResult(requestUri, getClass().getResourceAsStream("sone-parser-no-payload.xml")); - when(freenetInterface.fetchUri(requestUri)).thenReturn(fetchResult); - soneDownloader.fetchSone(sone, sone.getRequestUri(), true); - verify(core, never()).updateSone(any(Sone.class)); + public void fetchingACompleteSoneNotifiesTheUpdatedSoneProcessor() throws IOException, SoneException { + setupParsedSone(); + soneDownloader.fetchSone(sone, sone.getRequestUri(), false); + verify(updatedSoneProcessor).updateSone(parsedSone); verifyThatSoneStatusWasChangedToDownloadingAndBackTo(idle); } - private Fetched createFetchResult(FreenetURI uri, InputStream inputStream) throws IOException { + private void setupParsedSone() throws IOException, SoneException { + InputStream inputStream = mock(InputStream.class); ClientMetadata clientMetadata = new ClientMetadata("application/xml"); Bucket bucket = mock(Bucket.class); when(bucket.getInputStream()).thenReturn(inputStream); FetchResult fetchResult = new FetchResult(clientMetadata, bucket); - return new Fetched(uri, fetchResult); + Fetched fetched = new Fetched(finalRequestUri, fetchResult); + when(freenetInterface.fetchUri(eq(finalRequestUri))).thenReturn(fetched); + when(soneParser.parseSone(sone, inputStream)).thenReturn(parsedSone); + } + + @Test + public void soneDownloaderCanBeCreatedByDependencyInjection() { + assertThat(getBaseInjector().createChildInjector( + GuiceKt.supply(UpdatedSoneProcessor.class).byInstance(mock(UpdatedSoneProcessor.class)), + GuiceKt.supply(SoneParser.class).byInstance(mock(SoneParser.class)) + ).getInstance(SoneDownloader.class), notNullValue()); } } diff --git a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java index 5b94f08..31d7b6b 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java @@ -1,7 +1,7 @@ package net.pterodactylus.sone.core; import static com.google.common.io.ByteStreams.toByteArray; -import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static java.lang.System.currentTimeMillis; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -48,8 +48,6 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link SoneInserter} and its subclasses. - * - * @author David ‘Bombe’ Roden */ public class SoneInserterTest { @@ -66,7 +64,7 @@ public class SoneInserterTest { @Test public void insertionDelayIsForwardedToSoneInserter() { - EventBus eventBus = new AsyncEventBus(sameThreadExecutor()); + EventBus eventBus = new AsyncEventBus(directExecutor()); eventBus.register(new SoneInserter(core, eventBus, freenetInterface, "SoneId")); eventBus.post(new InsertionDelayChangedEvent(15)); assertThat(SoneInserter.getInsertionDelay().get(), is(15)); @@ -250,7 +248,7 @@ public class SoneInserterTest { @Test public void templateIsRenderedCorrectlyForManifestElement() throws IOException { - Map soneProperties = new HashMap(); + Map soneProperties = new HashMap<>(); soneProperties.put("id", "SoneId"); ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); long now = currentTimeMillis(); @@ -266,7 +264,7 @@ public class SoneInserterTest { @Test public void invalidTemplateReturnsANullManifestElement() { - Map soneProperties = new HashMap(); + Map soneProperties = new HashMap<>(); ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); assertThat(manifestCreator.createManifestElement("test.txt", "plain/text; charset=utf-8", @@ -276,7 +274,7 @@ public class SoneInserterTest { @Test public void errorWhileRenderingTemplateReturnsANullManifestElement() { - Map soneProperties = new HashMap(); + Map soneProperties = new HashMap<>(); ManifestCreator manifestCreator = new ManifestCreator(core, soneProperties); when(core.toString()).thenThrow(NullPointerException.class); assertThat(manifestCreator.createManifestElement("test.txt", diff --git a/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java b/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java index a45556a..1fd52c8 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneModificationDetectorTest.java @@ -16,8 +16,6 @@ import org.junit.Test; /** * Unit test for {@link SoneModificationDetector}. - * - * @author David ‘Bombe’ Roden */ public class SoneModificationDetectorTest { diff --git a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java index da5ca50..400b9ae 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java @@ -36,6 +36,7 @@ import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.database.AlbumBuilder; +import net.pterodactylus.sone.database.Database; import net.pterodactylus.sone.database.ImageBuilder; import net.pterodactylus.sone.database.PostBuilder; import net.pterodactylus.sone.database.PostReplyBuilder; @@ -59,30 +60,28 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link SoneParser}. - * - * @author David ‘Bombe’ Roden */ public class SoneParserTest { - private final Core core = mock(Core.class); - private final SoneParser soneParser = new SoneParser(core); + private final Database database = mock(Database.class); + private final SoneParser soneParser = new SoneParser(database); private final Sone sone = mock(Sone.class); private FreenetURI requestUri = mock(FreenetURI.class); private final PostBuilder postBuilder = mock(PostBuilder.class); - private final List createdPosts = new ArrayList(); + private final List createdPosts = new ArrayList<>(); private Post post = mock(Post.class); private final PostReplyBuilder postReplyBuilder = mock(PostReplyBuilder.class); - private final Set createdPostReplies = new HashSet(); + private final Set createdPostReplies = new HashSet<>(); private PostReply postReply = mock(PostReply.class); private final AlbumBuilder albumBuilder = mock(AlbumBuilder.class); private final ListMultimap nestedAlbums = ArrayListMultimap.create(); private final ListMultimap albumImages = ArrayListMultimap.create(); private Album album = mock(Album.class); - private final Map albums = new HashMap(); + private final Map albums = new HashMap<>(); private final ImageBuilder imageBuilder = mock(ImageBuilder.class); private Image image = mock(Image.class); - private final Map images = new HashMap(); + private final Map images = new HashMap<>(); @Before public void setupSone() { @@ -111,7 +110,7 @@ public class SoneParserTest { @Before public void setupSoneBuilder() { - when(core.soneBuilder()).thenAnswer(new Answer() { + when(database.newSoneBuilder()).thenAnswer(new Answer() { @Override public SoneBuilder answer(InvocationOnMock invocation) { return new MemorySoneBuilder(null); @@ -173,7 +172,7 @@ public class SoneParserTest { return post; } }); - when(core.postBuilder()).thenReturn(postBuilder); + when(database.newPostBuilder()).thenReturn(postBuilder); } @Before @@ -237,7 +236,7 @@ public class SoneParserTest { return postReply; } }); - when(core.postReplyBuilder()).thenReturn(postReplyBuilder); + when(database.newPostReplyBuilder()).thenReturn(postReplyBuilder); } @Before @@ -328,12 +327,12 @@ public class SoneParserTest { return album; } }); - when(core.albumBuilder()).thenReturn(albumBuilder); + when(database.newAlbumBuilder()).thenReturn(albumBuilder); } @Before public void setupAlbums() { - when(core.getAlbum(anyString())).thenAnswer(new Answer() { + when(database.getAlbum(anyString())).thenAnswer(new Answer() { @Override public Album answer(InvocationOnMock invocation) throws Throwable { @@ -439,12 +438,12 @@ public class SoneParserTest { return image; } }); - when(core.imageBuilder()).thenReturn(imageBuilder); + when(database.newImageBuilder()).thenReturn(imageBuilder); } @Before public void setupImages() { - when(core.getImage(anyString())).thenAnswer(new Answer() { + when(database.getImage(anyString())).thenAnswer(new Answer() { @Override public Image answer(InvocationOnMock invocation) throws Throwable { diff --git a/src/test/java/net/pterodactylus/sone/core/SoneRescuerTest.java b/src/test/java/net/pterodactylus/sone/core/SoneRescuerTest.java index 0b339fb..ff49a4c 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneRescuerTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneRescuerTest.java @@ -21,8 +21,6 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link SoneRescuer}. - * - * @author David ‘Bombe’ Roden */ public class SoneRescuerTest { diff --git a/src/test/java/net/pterodactylus/sone/core/SoneUriTest.java b/src/test/java/net/pterodactylus/sone/core/SoneUriTest.java index 879da4a..3525c9b 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneUriTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneUriTest.java @@ -13,8 +13,6 @@ import org.junit.Test; /** * Unit test for {@link SoneUri}. - * - * @author David ‘Bombe’ Roden */ public class SoneUriTest { diff --git a/src/test/java/net/pterodactylus/sone/core/UpdateCheckerTest.java b/src/test/java/net/pterodactylus/sone/core/UpdateCheckerTest.java index ad6b331..e7f1afe 100644 --- a/src/test/java/net/pterodactylus/sone/core/UpdateCheckerTest.java +++ b/src/test/java/net/pterodactylus/sone/core/UpdateCheckerTest.java @@ -17,8 +17,8 @@ import java.io.IOException; import java.io.InputStream; import net.pterodactylus.sone.core.FreenetInterface.Callback; -import net.pterodactylus.sone.core.FreenetInterface.Fetched; import net.pterodactylus.sone.core.event.UpdateFoundEvent; +import net.pterodactylus.sone.main.PluginHomepage; import net.pterodactylus.util.version.Version; import freenet.client.ClientMetadata; @@ -36,15 +36,14 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link UpdateChecker}. - * - * @author David ‘Bombe’ Roden */ public class UpdateCheckerTest { private final EventBus eventBus = mock(EventBus.class); private final FreenetInterface freenetInterface = mock(FreenetInterface.class); private final Version currentVersion = new Version(1, 0, 0); - private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface, currentVersion); + private final PluginHomepage pluginHomepage = new PluginHomepage("KSK@homepage"); + private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface, currentVersion, pluginHomepage); @Before public void startUpdateChecker() { diff --git a/src/test/java/net/pterodactylus/sone/core/WebOfTrustUpdaterTest.java b/src/test/java/net/pterodactylus/sone/core/WebOfTrustUpdaterTest.java index 7529fc6..664e4a1 100644 --- a/src/test/java/net/pterodactylus/sone/core/WebOfTrustUpdaterTest.java +++ b/src/test/java/net/pterodactylus/sone/core/WebOfTrustUpdaterTest.java @@ -35,8 +35,6 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link WebOfTrustUpdaterImpl} and its subclasses. - * - * @author David ‘Bombe’ Roden */ public class WebOfTrustUpdaterTest { diff --git a/src/test/java/net/pterodactylus/sone/data/ProfileTest.java b/src/test/java/net/pterodactylus/sone/data/ProfileTest.java deleted file mode 100644 index b06e2f4..0000000 --- a/src/test/java/net/pterodactylus/sone/data/ProfileTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.pterodactylus.sone.data; - -import net.pterodactylus.sone.data.Profile.Field; - -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.junit.Test; -import org.mockito.Mockito; - -/** - * Unit test for {@link Profile}. - * - * @author David ‘Bombe’ Roden - */ -public class ProfileTest { - - private final Sone sone = Mockito.mock(Sone.class); - private final Profile profile = new Profile(sone); - - @Test - public void newFieldsAreInitializedWithAnEmptyString() { - Field newField = profile.addField("testField"); - MatcherAssert.assertThat(newField.getValue(), Matchers.is("")); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilderTest.java b/src/test/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilderTest.java index b2d86dd..8489d3e 100644 --- a/src/test/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilderTest.java +++ b/src/test/java/net/pterodactylus/sone/data/impl/AbstractSoneBuilderTest.java @@ -10,8 +10,6 @@ import org.junit.Test; /** * Unit test for {@link AbstractSoneBuilder}. - * - * @author David ‘Bombe’ Roden */ public class AbstractSoneBuilderTest { diff --git a/src/test/java/net/pterodactylus/sone/data/impl/ImageImplTest.java b/src/test/java/net/pterodactylus/sone/data/impl/ImageImplTest.java index b78f0f6..b3801b2 100644 --- a/src/test/java/net/pterodactylus/sone/data/impl/ImageImplTest.java +++ b/src/test/java/net/pterodactylus/sone/data/impl/ImageImplTest.java @@ -7,8 +7,6 @@ import org.junit.Test; /** * Unit test for {@link ImageImpl}. - * - * @author David ‘Bombe’ Roden */ public class ImageImplTest { diff --git a/src/test/java/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.java b/src/test/java/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.java deleted file mode 100644 index 8dfce3d..0000000 --- a/src/test/java/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.pterodactylus.sone.database.memory; - -import static java.util.Arrays.asList; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.HashSet; -import java.util.Set; - -import net.pterodactylus.sone.test.TestValue; -import net.pterodactylus.util.config.Configuration; -import net.pterodactylus.util.config.ConfigurationException; -import net.pterodactylus.util.config.Value; - -import org.junit.Test; - -/** - * Unit test for {@link ConfigurationLoader}. - * - * @author David ‘Bombe’ Roden - */ -public class ConfigurationLoaderTest { - - private final Configuration configuration = mock(Configuration.class); - private final ConfigurationLoader configurationLoader = - new ConfigurationLoader(configuration); - - @Test - public void loaderCanLoadKnownPosts() { - when(configuration.getStringValue("KnownPosts/0/ID")) - .thenReturn(TestValue.from("Post2")); - when(configuration.getStringValue("KnownPosts/1/ID")) - .thenReturn(TestValue.from("Post1")); - when(configuration.getStringValue("KnownPosts/2/ID")) - .thenReturn(TestValue.from(null)); - Set knownPosts = configurationLoader.loadKnownPosts(); - assertThat(knownPosts, containsInAnyOrder("Post1", "Post2")); - } - - @Test - public void loaderCanLoadKnownPostReplies() { - when(configuration.getStringValue("KnownReplies/0/ID")) - .thenReturn(TestValue.from("PostReply2")); - when(configuration.getStringValue("KnownReplies/1/ID")) - .thenReturn(TestValue.from("PostReply1")); - when(configuration.getStringValue("KnownReplies/2/ID")) - .thenReturn(TestValue.from(null)); - Set knownPosts = configurationLoader.loadKnownPostReplies(); - assertThat(knownPosts, - containsInAnyOrder("PostReply1", "PostReply2")); - } - - @Test - public void loaderCanLoadBookmarkedPosts() { - when(configuration.getStringValue("Bookmarks/Post/0/ID")) - .thenReturn(TestValue.from("Post2")); - when(configuration.getStringValue("Bookmarks/Post/1/ID")) - .thenReturn(TestValue.from("Post1")); - when(configuration.getStringValue("Bookmarks/Post/2/ID")) - .thenReturn(TestValue.from(null)); - Set knownPosts = configurationLoader.loadBookmarkedPosts(); - assertThat(knownPosts, containsInAnyOrder("Post1", "Post2")); - } - - @Test - public void loaderCanSaveBookmarkedPosts() throws ConfigurationException { - final Value post1 = TestValue.from(null); - final Value post2 = TestValue.from(null); - final Value post3 = TestValue.from(null); - when(configuration.getStringValue("Bookmarks/Post/0/ID")).thenReturn(post1); - when(configuration.getStringValue("Bookmarks/Post/1/ID")).thenReturn(post2); - when(configuration.getStringValue("Bookmarks/Post/2/ID")).thenReturn(post3); - HashSet originalPosts = new HashSet(asList("Post1", "Post2")); - configurationLoader.saveBookmarkedPosts(originalPosts); - HashSet extractedPosts = - new HashSet(asList(post1.getValue(), post2.getValue())); - assertThat(extractedPosts, containsInAnyOrder("Post1", "Post2")); - assertThat(post3.getValue(), nullValue()); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java b/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java index 7edea06..188b740 100644 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java +++ b/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java @@ -25,8 +25,6 @@ import org.mockito.stubbing.Answer; /** * Unit test for {@link MemoryBookmarkDatabase}. - * - * @author David ‘Bombe’ Roden */ public class MemoryBookmarkDatabaseTest { @@ -35,7 +33,7 @@ public class MemoryBookmarkDatabaseTest { mock(ConfigurationLoader.class); private final MemoryBookmarkDatabase bookmarkDatabase = new MemoryBookmarkDatabase(memoryDatabase, configurationLoader); - private final Map posts = new HashMap(); + private final Map posts = new HashMap<>(); @Before public void setupMemoryDatabase() { @@ -69,7 +67,7 @@ public class MemoryBookmarkDatabaseTest { @Test public void bookmarkDatabaseRetainsBookmarkedPosts() { - Set allPosts = new HashSet(posts.values()); + Set allPosts = new HashSet<>(posts.values()); for (Post post : allPosts) { bookmarkDatabase.bookmarkPost(post); } @@ -100,7 +98,7 @@ public class MemoryBookmarkDatabaseTest { @Test public void removingABookmarkRemovesTheCorrectBookmark() { - Set allPosts = new HashSet(posts.values()); + Set allPosts = new HashSet<>(posts.values()); for (Post post : allPosts) { bookmarkDatabase.bookmarkPost(post); } diff --git a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java deleted file mode 100644 index bb62eaf..0000000 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Sone - MemoryDatabaseTest.java - Copyright © 2013–2016 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 . - */ - -package net.pterodactylus.sone.database.memory; - -import static com.google.common.base.Optional.of; -import static java.util.Arrays.asList; -import static java.util.UUID.randomUUID; -import static net.pterodactylus.sone.test.Matchers.isAlbum; -import static net.pterodactylus.sone.test.Matchers.isImage; -import static net.pterodactylus.sone.test.Matchers.isPost; -import static net.pterodactylus.sone.test.Matchers.isPostReply; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.emptyIterable; -import static org.hamcrest.Matchers.nullValue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -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.Sone; -import net.pterodactylus.sone.data.impl.AlbumImpl; -import net.pterodactylus.sone.test.TestAlbumBuilder; -import net.pterodactylus.sone.test.TestImageBuilder; -import net.pterodactylus.sone.test.TestPostBuilder; -import net.pterodactylus.sone.test.TestPostReplyBuilder; -import net.pterodactylus.sone.test.TestValue; -import net.pterodactylus.util.config.Configuration; -import net.pterodactylus.util.config.Value; - -import com.google.common.base.Optional; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * Tests for {@link MemoryDatabase}. - * - * @author David ‘Bombe’ Roden - */ -public class MemoryDatabaseTest { - - private static final String SONE_ID = "sone"; - private static final String RECIPIENT_ID = "recipient"; - private final Configuration configuration = mock(Configuration.class); - private final MemoryDatabase memoryDatabase = new MemoryDatabase(null, configuration); - private final Sone sone = mock(Sone.class); - - @Before - public void setupSone() { - when(sone.getId()).thenReturn(SONE_ID); - } - - @Test - public void storedSoneIsMadeAvailable() { - Post firstPost = new TestPostBuilder().withId("post1") - .from(SONE_ID) - .withTime(1000L) - .withText("post1") - .build(); - Post secondPost = new TestPostBuilder().withId("post2") - .from(SONE_ID) - .withTime(2000L) - .withText("post2") - .to(RECIPIENT_ID) - .build(); - List posts = asList(firstPost, secondPost); - when(sone.getPosts()).thenReturn(posts); - PostReply firstPostFirstReply = - new TestPostReplyBuilder().withId("reply1") - .from(SONE_ID) - .to(firstPost.getId()) - .withTime(3000L) - .withText("reply1") - .build(); - PostReply firstPostSecondReply = - new TestPostReplyBuilder().withId("reply3") - .from(RECIPIENT_ID) - .to(firstPost.getId()) - .withTime(5000L) - .withText("reply3") - .build(); - PostReply secondPostReply = - new TestPostReplyBuilder().withId("reply2") - .from(SONE_ID) - .to(secondPost.getId()) - .withTime(4000L) - .withText("reply2") - .build(); - Set postReplies = new HashSet( - asList(firstPostFirstReply, firstPostSecondReply, - secondPostReply)); - when(sone.getReplies()).thenReturn(postReplies); - Album firstAlbum = new TestAlbumBuilder().withId("album1") - .by(sone) - .build() - .modify() - .setTitle("album1") - .setDescription("album-description1") - .update(); - Album secondAlbum = new TestAlbumBuilder().withId("album2").by( - sone).build().modify().setTitle("album2").setDescription( - "album-description2").update(); - Album thirdAlbum = new TestAlbumBuilder().withId("album3").by( - sone).build().modify().setTitle("album3").setDescription( - "album-description3").update(); - firstAlbum.addAlbum(thirdAlbum); - Album rootAlbum = mock(Album.class); - when(rootAlbum.getAlbums()).thenReturn( - asList(firstAlbum, secondAlbum)); - when(sone.getRootAlbum()).thenReturn(rootAlbum); - Image firstImage = new TestImageBuilder().withId("image1") - .build() - .modify() - .setSone(sone) - .setCreationTime(1000L) - .setKey("KSK@image1") - .setTitle("image1") - .setDescription("image-description1") - .setWidth(16) - .setHeight(9) - .update(); - Image secondImage = new TestImageBuilder().withId("image2") - .build() - .modify() - .setSone(sone) - .setCreationTime(2000L) - .setKey("KSK@image2") - .setTitle("image2") - .setDescription("image-description2") - .setWidth(32) - .setHeight(18) - .update(); - Image thirdImage = new TestImageBuilder().withId("image3") - .build() - .modify() - .setSone(sone) - .setCreationTime(3000L) - .setKey("KSK@image3") - .setTitle("image3") - .setDescription("image-description3") - .setWidth(48) - .setHeight(27) - .update(); - firstAlbum.addImage(firstImage); - firstAlbum.addImage(thirdImage); - secondAlbum.addImage(secondImage); - memoryDatabase.storeSone(sone); - assertThat(memoryDatabase.getPost("post1"), - isPost(firstPost.getId(), 1000L, "post1", - Optional.absent())); - assertThat(memoryDatabase.getPost("post2"), - isPost(secondPost.getId(), 2000L, "post2", of(RECIPIENT_ID))); - assertThat(memoryDatabase.getPost("post3"), nullValue()); - assertThat(memoryDatabase.getPostReply("reply1"), - isPostReply("reply1", "post1", 3000L, "reply1")); - assertThat(memoryDatabase.getPostReply("reply2"), - isPostReply("reply2", "post2", 4000L, "reply2")); - assertThat(memoryDatabase.getPostReply("reply3"), - isPostReply("reply3", "post1", 5000L, "reply3")); - assertThat(memoryDatabase.getPostReply("reply4"), nullValue()); - assertThat(memoryDatabase.getAlbum("album1"), - isAlbum("album1", null, "album1", "album-description1")); - assertThat(memoryDatabase.getAlbum("album2"), - isAlbum("album2", null, "album2", "album-description2")); - assertThat(memoryDatabase.getAlbum("album3"), - isAlbum("album3", "album1", "album3", "album-description3")); - assertThat(memoryDatabase.getAlbum("album4"), nullValue()); - assertThat(memoryDatabase.getImage("image1"), - isImage("image1", 1000L, "KSK@image1", "image1", - "image-description1", 16, 9)); - assertThat(memoryDatabase.getImage("image2"), - isImage("image2", 2000L, "KSK@image2", "image2", - "image-description2", 32, 18)); - assertThat(memoryDatabase.getImage("image3"), - isImage("image3", 3000L, "KSK@image3", "image3", - "image-description3", 48, 27)); - assertThat(memoryDatabase.getImage("image4"), nullValue()); - } - - @Test - public void storedAndRemovedSoneIsNotAvailable() { - storedSoneIsMadeAvailable(); - memoryDatabase.removeSone(sone); - assertThat(memoryDatabase.getSones(), empty()); - } - - @Test - public void postRecipientsAreDetectedCorrectly() { - Post postWithRecipient = createPost(of(RECIPIENT_ID)); - memoryDatabase.storePost(postWithRecipient); - Post postWithoutRecipient = createPost(Optional.absent()); - memoryDatabase.storePost(postWithoutRecipient); - assertThat(memoryDatabase.getDirectedPosts(RECIPIENT_ID), - contains(postWithRecipient)); - } - - private Post createPost(Optional recipient) { - Post postWithRecipient = mock(Post.class); - when(postWithRecipient.getId()).thenReturn(randomUUID().toString()); - when(postWithRecipient.getSone()).thenReturn(sone); - when(postWithRecipient.getRecipientId()).thenReturn(recipient); - return postWithRecipient; - } - - @Test - public void postRepliesAreManagedCorrectly() { - Post firstPost = createPost(Optional.absent()); - PostReply firstPostFirstReply = createPostReply(firstPost, 1000L); - Post secondPost = createPost(Optional.absent()); - PostReply secondPostFirstReply = createPostReply(secondPost, 1000L); - PostReply secondPostSecondReply = createPostReply(secondPost, 2000L); - memoryDatabase.storePost(firstPost); - memoryDatabase.storePost(secondPost); - memoryDatabase.storePostReply(firstPostFirstReply); - memoryDatabase.storePostReply(secondPostFirstReply); - memoryDatabase.storePostReply(secondPostSecondReply); - assertThat(memoryDatabase.getReplies(firstPost.getId()), - contains(firstPostFirstReply)); - assertThat(memoryDatabase.getReplies(secondPost.getId()), - contains(secondPostFirstReply, secondPostSecondReply)); - } - - private PostReply createPostReply(Post post, long time) { - PostReply postReply = mock(PostReply.class); - when(postReply.getId()).thenReturn(randomUUID().toString()); - when(postReply.getTime()).thenReturn(time); - when(postReply.getPost()).thenReturn(of(post)); - final String postId = post.getId(); - when(postReply.getPostId()).thenReturn(postId); - return postReply; - } - - @Test - public void testBasicAlbumFunctionality() { - Album newAlbum = new AlbumImpl(mock(Sone.class)); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), nullValue()); - memoryDatabase.storeAlbum(newAlbum); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(newAlbum)); - memoryDatabase.removeAlbum(newAlbum); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), nullValue()); - } - - private void initializeFriends() { - when(configuration.getStringValue("Sone/" + SONE_ID + "/Friends/0/ID")).thenReturn( - TestValue.from("Friend1")); - when(configuration.getStringValue("Sone/" + SONE_ID + "/Friends/1/ID")).thenReturn( - TestValue.from("Friend2")); - when(configuration.getStringValue("Sone/" + SONE_ID + "/Friends/2/ID")).thenReturn( - TestValue.from(null)); - } - - @Test - public void friendsAreReturnedCorrectly() { - initializeFriends(); - when(sone.isLocal()).thenReturn(true); - Collection friends = memoryDatabase.getFriends(sone); - assertThat(friends, containsInAnyOrder("Friend1", "Friend2")); - } - - @Test - public void friendsAreOnlyLoadedOnceFromConfiguration() { - friendsAreReturnedCorrectly(); - memoryDatabase.getFriends(sone); - verify(configuration).getStringValue("Sone/" + SONE_ID + "/Friends/0/ID"); - } - - @Test - public void friendsAreOnlyReturnedForLocalSones() { - Collection friends = memoryDatabase.getFriends(sone); - assertThat(friends, emptyIterable()); - verify(configuration, never()).getStringValue("Sone/" + SONE_ID + "/Friends/0/ID"); - } - - @Test - public void checkingForAFriendReturnsTrue() { - initializeFriends(); - when(sone.isLocal()).thenReturn(true); - assertThat(memoryDatabase.isFriend(sone, "Friend1"), is(true)); - } - - @Test - public void checkingForAFriendThatIsNotAFriendReturnsFalse() { - initializeFriends(); - when(sone.isLocal()).thenReturn(true); - assertThat(memoryDatabase.isFriend(sone, "FriendX"), is(false)); - } - - @Test - public void checkingForAFriendOfRemoteSoneReturnsFalse() { - initializeFriends(); - assertThat(memoryDatabase.isFriend(sone, "Friend1"), is(false)); - } - - private Map> prepareConfigurationValues() { - final Map> configurationValues = new HashMap>(); - when(configuration.getStringValue(anyString())).thenAnswer(new Answer>() { - @Override - public Value answer(InvocationOnMock invocation) throws Throwable { - Value stringValue = TestValue.from(null); - configurationValues.put((String) invocation.getArguments()[0], stringValue); - return stringValue; - } - }); - return configurationValues; - } - - @Test - public void friendIsAddedCorrectlyToLocalSone() { - Map> configurationValues = prepareConfigurationValues(); - when(sone.isLocal()).thenReturn(true); - memoryDatabase.addFriend(sone, "Friend1"); - assertThat(configurationValues.get("Sone/" + SONE_ID + "/Friends/0/ID"), - is(TestValue.from("Friend1"))); - assertThat(configurationValues.get("Sone/" + SONE_ID + "/Friends/1/ID"), - is(TestValue.from(null))); - } - - @Test - public void friendIsNotAddedToRemoteSone() { - memoryDatabase.addFriend(sone, "Friend1"); - verify(configuration, never()).getStringValue(anyString()); - } - - @Test - public void configurationIsWrittenOnceIfFriendIsAddedTwice() { - prepareConfigurationValues(); - when(sone.isLocal()).thenReturn(true); - memoryDatabase.addFriend(sone, "Friend1"); - memoryDatabase.addFriend(sone, "Friend1"); - verify(configuration, times(3)).getStringValue(anyString()); - } - - @Test - public void friendIsRemovedCorrectlyFromLocalSone() { - Map> configurationValues = prepareConfigurationValues(); - when(sone.isLocal()).thenReturn(true); - memoryDatabase.addFriend(sone, "Friend1"); - memoryDatabase.removeFriend(sone, "Friend1"); - assertThat(configurationValues.get("Sone/" + SONE_ID + "/Friends/0/ID"), - is(TestValue.from(null))); - assertThat(configurationValues.get("Sone/" + SONE_ID + "/Friends/1/ID"), - is(TestValue.from(null))); - } - - @Test - public void configurationIsNotWrittenWhenANonFriendIsRemoved() { - prepareConfigurationValues(); - when(sone.isLocal()).thenReturn(true); - memoryDatabase.removeFriend(sone, "Friend1"); - verify(configuration).getStringValue(anyString()); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/freenet/KeyTest.java b/src/test/java/net/pterodactylus/sone/freenet/KeyTest.java index 8fff7bd..80e1e45 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/KeyTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/KeyTest.java @@ -14,8 +14,6 @@ import org.junit.Test; /** * Unit test for {@link Key}. - * - * @author David ‘Bombe’ Roden */ public class KeyTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultIdentityTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultIdentityTest.java index 8def0e0..9d59570 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultIdentityTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultIdentityTest.java @@ -1,5 +1,5 @@ /* - * Sone - DefaultIdentityTest.java - Copyright © 2013–2016 David Roden + * Sone - DefaultIdentityTest.java - Copyright © 2013–2019 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 @@ -36,8 +36,6 @@ import org.junit.Test; /** * Unit test for {@link DefaultIdentity}. - * - * @author David ‘Bombe’ Roden */ public class DefaultIdentityTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentityTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentityTest.java index c5dc840..138ced3 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentityTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentityTest.java @@ -1,5 +1,5 @@ /* - * Sone - DefaultOwnIdentityTest.java - Copyright © 2013–2016 David Roden + * Sone - DefaultOwnIdentityTest.java - Copyright © 2013–2019 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 @@ -24,8 +24,6 @@ import org.junit.Test; /** * Unit test for {@link DefaultOwnIdentity}. - * - * @author David ‘Bombe’ Roden */ public class DefaultOwnIdentityTest extends DefaultIdentityTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/Identities.java b/src/test/java/net/pterodactylus/sone/freenet/wot/Identities.java index 9f92308..7ed2b59 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/Identities.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/Identities.java @@ -1,5 +1,5 @@ /* - * Sone - Identities.java - Copyright © 2013–2016 David Roden + * Sone - Identities.java - Copyright © 2013–2019 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 @@ -22,8 +22,6 @@ import java.util.Map; /** * Creates {@link Identity}s and {@link OwnIdentity}s. - * - * @author David ‘Bombe’ Roden */ public class Identities { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetectorTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetectorTest.java index 3773cbe..e1eb1c8 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetectorTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeDetectorTest.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityChangeDetectorTest.java - Copyright © 2013–2016 David Roden + * Sone - IdentityChangeDetectorTest.java - Copyright © 2013–2019 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 @@ -34,8 +34,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityChangeDetector}. - * - * @author David ‘Bombe’ Roden */ public class IdentityChangeDetectorTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSenderTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSenderTest.java index c5dc82b..ff442a4 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSenderTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityChangeEventSenderTest.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityChangeEventSenderTest.java - Copyright © 2013–2016 David Roden + * Sone - IdentityChangeEventSenderTest.java - Copyright © 2013–2019 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 @@ -42,8 +42,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityChangeEventSender}. - * - * @author David ‘Bombe’ Roden */ public class IdentityChangeEventSenderTest { @@ -77,14 +75,14 @@ public class IdentityChangeEventSenderTest { } private Map> createNewIdentities() { - Map> oldIdentities = new HashMap>(); + Map> oldIdentities = new HashMap<>(); oldIdentities.put(ownIdentities.get(1), asList(identities.get(3), identities.get(2))); oldIdentities.put(ownIdentities.get(2), asList(identities.get(1), identities.get(2))); return oldIdentities; } private Map> createOldIdentities() { - Map> oldIdentities = new HashMap>(); + Map> oldIdentities = new HashMap<>(); oldIdentities.put(ownIdentities.get(0), asList(identities.get(0), identities.get(1))); oldIdentities.put(ownIdentities.get(1), asList(identities.get(0), identities.get(1))); return oldIdentities; diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityLoaderTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityLoaderTest.java index 72175bd..8744c15 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityLoaderTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityLoaderTest.java @@ -1,5 +1,5 @@ /* - * Sone - IdentityLoaderTest.java - Copyright © 2013–2016 David Roden + * Sone - IdentityLoaderTest.java - Copyright © 2013–2019 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 @@ -47,8 +47,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityLoader}. - * - * @author David ‘Bombe’ Roden */ public class IdentityLoaderTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.java index 83c696d..45e95db 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/IdentityManagerTest.java @@ -14,8 +14,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityManagerImpl}. - * - * @author David ‘Bombe’ Roden */ public class IdentityManagerTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/event/IdentityEventTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/event/IdentityEventTest.java index 461e303..4fa5bc9 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/event/IdentityEventTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/event/IdentityEventTest.java @@ -12,8 +12,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityEvent}. - * - * @author David ‘Bombe’ Roden */ public class IdentityEventTest { diff --git a/src/test/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEventTest.java b/src/test/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEventTest.java index c4ec43b..3d27c34 100644 --- a/src/test/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEventTest.java +++ b/src/test/java/net/pterodactylus/sone/freenet/wot/event/OwnIdentityEventTest.java @@ -11,8 +11,6 @@ import org.junit.Test; /** * Unit test for {@link OwnIdentityEvent}. - * - * @author David ‘Bombe’ Roden */ public class OwnIdentityEventTest { diff --git a/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java b/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java index c3fa7e9..7a84978 100644 --- a/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java +++ b/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java @@ -21,7 +21,9 @@ import net.pterodactylus.util.web.Method; import net.pterodactylus.util.web.Page; import net.pterodactylus.util.web.Response; +import freenet.clients.http.SessionManager; import freenet.clients.http.ToadletContext; +import freenet.l10n.BaseL10n; import freenet.support.api.HTTPRequest; import com.google.common.base.Charsets; @@ -33,14 +35,13 @@ import org.junit.rules.TemporaryFolder; /** * Unit test for {@link DebugLoaders}. - * - * @author David ‘Bombe’ Roden */ public class DebugLoadersTest { @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + private final BaseL10n l10n = mock(BaseL10n.class); private final StringWriter stringWriter = new StringWriter(); private final TemplateContext templateContext = new TemplateContext(); private Loaders loaders; @@ -70,7 +71,8 @@ public class DebugLoadersTest { Method method = Method.GET; HTTPRequest httpRequest = mock(HTTPRequest.class); ToadletContext toadletContext = mock(ToadletContext.class); - FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext); + SessionManager sessionManager = mock(SessionManager.class); + FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager); OutputStream outputStream = new ByteArrayOutputStream(); Response response = new Response(outputStream); page.handleRequest(request, response); diff --git a/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java b/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java index 0f0a9f1..dc51479 100644 --- a/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java +++ b/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java @@ -21,18 +21,19 @@ import net.pterodactylus.util.web.Method; import net.pterodactylus.util.web.Page; import net.pterodactylus.util.web.Response; +import freenet.clients.http.SessionManager; import freenet.clients.http.ToadletContext; +import freenet.l10n.BaseL10n; import freenet.support.api.HTTPRequest; import org.junit.Test; /** * Unit test for {@link DefaultLoaders}. - * - * @author David ‘Bombe’ Roden */ public class DefaultLoadersTest { + private final BaseL10n l10n = mock(BaseL10n.class); private final Loaders loaders = new DefaultLoaders(); private final StringWriter stringWriter = new StringWriter(); private final TemplateContext templateContext = new TemplateContext(); @@ -51,7 +52,8 @@ public class DefaultLoadersTest { Method method = Method.GET; HTTPRequest httpRequest = mock(HTTPRequest.class); ToadletContext toadletContext = mock(ToadletContext.class); - FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext); + SessionManager sessionManager = mock(SessionManager.class); + FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager); OutputStream outputStream = new ByteArrayOutputStream(); Response response = new Response(outputStream); staticPage.handleRequest(request, response); diff --git a/src/test/java/net/pterodactylus/sone/main/ReparseFilterTest.java b/src/test/java/net/pterodactylus/sone/main/ReparseFilterTest.java index 879fe36..87dae7e 100644 --- a/src/test/java/net/pterodactylus/sone/main/ReparseFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/main/ReparseFilterTest.java @@ -11,8 +11,6 @@ import org.junit.Test; /** * Unit test for {@link ReparseFilter}. - * - * @author David ‘Bombe’ Roden */ public class ReparseFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/notify/ListNotificationFilterTest.java b/src/test/java/net/pterodactylus/sone/notify/ListNotificationFilterTest.java index dabfd5a..af6339b 100644 --- a/src/test/java/net/pterodactylus/sone/notify/ListNotificationFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/notify/ListNotificationFilterTest.java @@ -33,8 +33,6 @@ import org.mockito.ArgumentMatchers; /** * Unit test for {@link ListNotificationFilterTest}. - * - * @author David ‘Bombe’ Roden */ public class ListNotificationFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/notify/ListNotificationTest.java b/src/test/java/net/pterodactylus/sone/notify/ListNotificationTest.java index ea5f067..5e40f81 100644 --- a/src/test/java/net/pterodactylus/sone/notify/ListNotificationTest.java +++ b/src/test/java/net/pterodactylus/sone/notify/ListNotificationTest.java @@ -21,8 +21,6 @@ import org.junit.Test; /** * Unit test for {@link ListNotification}. - * - * @author David ‘Bombe’ Roden */ public class ListNotificationTest { @@ -36,7 +34,7 @@ public class ListNotificationTest { public ListNotificationTest() { when(template.getInitialContext()).thenReturn(templateInitialContext); - listNotification = new ListNotification(ID, KEY, template); + listNotification = new ListNotification<>(ID, KEY, template); } @Test diff --git a/src/test/java/net/pterodactylus/sone/notify/PostVisibilityFilterTest.java b/src/test/java/net/pterodactylus/sone/notify/PostVisibilityFilterTest.java index d49e59b..21baa4e 100644 --- a/src/test/java/net/pterodactylus/sone/notify/PostVisibilityFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/notify/PostVisibilityFilterTest.java @@ -19,8 +19,6 @@ import org.junit.Test; /** * Unit test for {@link PostVisibilityFilterTest}. - * - * @author David ‘Bombe’ Roden */ public class PostVisibilityFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/notify/ReplyVisibilityFilterTest.java b/src/test/java/net/pterodactylus/sone/notify/ReplyVisibilityFilterTest.java index 7187847..3f430be 100644 --- a/src/test/java/net/pterodactylus/sone/notify/ReplyVisibilityFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/notify/ReplyVisibilityFilterTest.java @@ -18,8 +18,6 @@ import org.junit.Test; /** * Unit test for {@link ReplyVisibilityFilterTest}. - * - * @author David ‘Bombe’ Roden */ public class ReplyVisibilityFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/template/AlbumAccessorTest.java b/src/test/java/net/pterodactylus/sone/template/AlbumAccessorTest.java index 56d2f29..28f6fd1 100644 --- a/src/test/java/net/pterodactylus/sone/template/AlbumAccessorTest.java +++ b/src/test/java/net/pterodactylus/sone/template/AlbumAccessorTest.java @@ -28,8 +28,6 @@ import org.junit.Test; /** * Unit test for {@link AlbumAccessor}. - * - * @author David ‘Bombe’ Roden */ public class AlbumAccessorTest { diff --git a/src/test/java/net/pterodactylus/sone/template/CollectionAccessorTest.java b/src/test/java/net/pterodactylus/sone/template/CollectionAccessorTest.java index d0e5057..e83693a 100644 --- a/src/test/java/net/pterodactylus/sone/template/CollectionAccessorTest.java +++ b/src/test/java/net/pterodactylus/sone/template/CollectionAccessorTest.java @@ -16,13 +16,11 @@ import org.junit.Test; /** * Unit test for {@link CollectionAccessor}. - * - * @author David ‘Bombe’ Roden */ public class CollectionAccessorTest { private final CollectionAccessor accessor = new CollectionAccessor(); - private final Collection collection = new ArrayList(); + private final Collection collection = new ArrayList<>(); @Before public void setupCollection() { diff --git a/src/test/java/net/pterodactylus/sone/template/CssClassNameFilterTest.java b/src/test/java/net/pterodactylus/sone/template/CssClassNameFilterTest.java index 7b47567..0d67548 100644 --- a/src/test/java/net/pterodactylus/sone/template/CssClassNameFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/template/CssClassNameFilterTest.java @@ -10,8 +10,6 @@ import org.junit.Test; /** * Unit test for {@link CssClassNameFilter}. - * - * @author David ‘Bombe’ Roden */ public class CssClassNameFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/template/FilesystemTemplateTest.java b/src/test/java/net/pterodactylus/sone/template/FilesystemTemplateTest.java index 7b93477..9259ef5 100644 --- a/src/test/java/net/pterodactylus/sone/template/FilesystemTemplateTest.java +++ b/src/test/java/net/pterodactylus/sone/template/FilesystemTemplateTest.java @@ -22,14 +22,12 @@ import org.junit.Test; /** * Unit test for {@link FilesystemTemplate}. - * - * @author David ‘Bombe’ Roden */ public class FilesystemTemplateTest { private final File tempFile; private final FilesystemTemplate filesystemTemplate; - private final AtomicReference stringWriter = new AtomicReference(new StringWriter()); + private final AtomicReference stringWriter = new AtomicReference<>(new StringWriter()); private final TemplateContext templateContext = new TemplateContext(); public FilesystemTemplateTest() throws IOException { diff --git a/src/test/java/net/pterodactylus/sone/template/GetPagePluginTest.java b/src/test/java/net/pterodactylus/sone/template/GetPagePluginTest.java index febd06a..cefc8b0 100644 --- a/src/test/java/net/pterodactylus/sone/template/GetPagePluginTest.java +++ b/src/test/java/net/pterodactylus/sone/template/GetPagePluginTest.java @@ -17,8 +17,6 @@ import org.junit.Test; /** * Unit test for {@link GetPagePlugin}. - * - * @author David ‘Bombe’ Roden */ public class GetPagePluginTest { @@ -26,7 +24,7 @@ public class GetPagePluginTest { private final TemplateContext context = mock(TemplateContext.class); private final FreenetRequest request = mock(FreenetRequest.class); private final Map parameters = - new HashMap(); + new HashMap<>(); private HTTPRequest httpRequest = mock(HTTPRequest.class); @Before diff --git a/src/test/java/net/pterodactylus/sone/template/HttpRequestAccessorTest.java b/src/test/java/net/pterodactylus/sone/template/HttpRequestAccessorTest.java index 37c6260..73e3f4c 100644 --- a/src/test/java/net/pterodactylus/sone/template/HttpRequestAccessorTest.java +++ b/src/test/java/net/pterodactylus/sone/template/HttpRequestAccessorTest.java @@ -16,8 +16,6 @@ import org.junit.Test; /** * Unit test for {@link HttpRequestAccessor}. - * - * @author David ‘Bombe’ Roden */ public class HttpRequestAccessorTest { diff --git a/src/test/java/net/pterodactylus/sone/template/IdentityAccessorTest.java b/src/test/java/net/pterodactylus/sone/template/IdentityAccessorTest.java index 6744bd8..4a8c624 100644 --- a/src/test/java/net/pterodactylus/sone/template/IdentityAccessorTest.java +++ b/src/test/java/net/pterodactylus/sone/template/IdentityAccessorTest.java @@ -24,8 +24,6 @@ import org.junit.Test; /** * Unit test for {@link IdentityAccessor}. - * - * @author David ‘Bombe’ Roden */ public class IdentityAccessorTest { diff --git a/src/test/java/net/pterodactylus/sone/template/ImageLinkFilterTest.java b/src/test/java/net/pterodactylus/sone/template/ImageLinkFilterTest.java index e96b6cb..5d95423 100644 --- a/src/test/java/net/pterodactylus/sone/template/ImageLinkFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/template/ImageLinkFilterTest.java @@ -9,9 +9,6 @@ import static org.mockito.Mockito.when; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Image; -import net.pterodactylus.util.template.HtmlFilter; -import net.pterodactylus.util.template.TemplateContext; -import net.pterodactylus.util.template.TemplateContextFactory; import com.google.common.collect.ImmutableMap; import org.hamcrest.Matchers; @@ -23,23 +20,14 @@ import org.junit.Test; /** * Unit test for {@link ImageLinkFilterTest}. - * - * @author David ‘Bombe’ Roden */ public class ImageLinkFilterTest { private final Core core = mock(Core.class); - private final TemplateContextFactory templateContextFactory = new TemplateContextFactory(); - private final ImageLinkFilter imageLinkFilter = new ImageLinkFilter(core, templateContextFactory); - private final TemplateContext templateContext = null; + private final ImageLinkFilter imageLinkFilter = new ImageLinkFilter(core); private final Image image = mock(Image.class); @Before - public void setupTemplateContextFactory() { - templateContextFactory.addFilter("html", new HtmlFilter()); - } - - @Before public void setupCore() { when(core.getImage("image-id", false)).thenReturn(image); } @@ -58,7 +46,7 @@ public class ImageLinkFilterTest { @Test public void imageLinkIsGeneratedCorrectlyForNotInsertedImages() { when(image.isInserted()).thenReturn(false); - String result = String.valueOf(imageLinkFilter.format(templateContext, image, ImmutableMap.of())); + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of())); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("class"), is("")); assertThat(imageElement.attr("src"), is("getImage.html?image=image-id")); @@ -70,7 +58,7 @@ public class ImageLinkFilterTest { @Test public void imageLinkIsGeneratedCorrectlyForInsertedImages() { - String result = String.valueOf(imageLinkFilter.format(templateContext, image, ImmutableMap.of())); + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of())); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("class"), is("")); assertThat(imageElement.attr("src"), is("/image-key")); @@ -82,7 +70,7 @@ public class ImageLinkFilterTest { @Test public void imageTitleAndDescriptionAreOverriddenCorrectly() { - String result = String.valueOf(imageLinkFilter.format(templateContext, image, ImmutableMap.of("title", "Test Title"))); + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of("title", "Test Title"))); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("title"), is("Test Title")); assertThat(imageElement.attr("alt"), is("Test Title")); @@ -90,7 +78,7 @@ public class ImageLinkFilterTest { @Test public void imageIsScaledByWidthCorrectly() { - String result = String.valueOf(imageLinkFilter.format(templateContext, image, ImmutableMap.of("max-width", "320"))); + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of("max-width", "320"))); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("width"), is("320")); assertThat(imageElement.attr("height"), is("135")); @@ -98,7 +86,7 @@ public class ImageLinkFilterTest { @Test public void imageIsScaledByHeightCorrectly() { - String result = String.valueOf(imageLinkFilter.format(templateContext, image, ImmutableMap.of("max-height", "135"))); + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of("max-height", "135"))); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("width"), is("320")); assertThat(imageElement.attr("height"), is("135")); @@ -106,7 +94,7 @@ public class ImageLinkFilterTest { @Test public void wideImageIsEnlargedCorrectly() { - String result = String.valueOf(imageLinkFilter.format(templateContext, image, + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of("mode", "enlarge", "max-width", "100", "max-height", "100"))); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("width"), is("237")); @@ -119,7 +107,7 @@ public class ImageLinkFilterTest { public void highImageIsEnlargedCorrectly() { when(image.getWidth()).thenReturn(270); when(image.getHeight()).thenReturn(640); - String result = String.valueOf(imageLinkFilter.format(templateContext, image, + String result = String.valueOf(imageLinkFilter.format(null, image, ImmutableMap.of("mode", "enlarge", "max-width", "100", "max-height", "100"))); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("width"), is("100")); @@ -130,12 +118,12 @@ public class ImageLinkFilterTest { @Test public void nullImageIsReturnedAsNull() { - assertThat(imageLinkFilter.format(templateContext, null, null), nullValue()); + assertThat(imageLinkFilter.format(null, null, null), nullValue()); } @Test public void stringIsUsedToLoadImageFromCore() { - String result = String.valueOf(imageLinkFilter.format(templateContext, "image-id", ImmutableMap.of())); + String result = String.valueOf(imageLinkFilter.format(null, "image-id", ImmutableMap.of())); Element imageElement = getSingleElement(result); assertThat(imageElement.attr("class"), is("")); assertThat(imageElement.attr("src"), is("/image-key")); diff --git a/src/test/java/net/pterodactylus/sone/template/JavascriptFilterTest.java b/src/test/java/net/pterodactylus/sone/template/JavascriptFilterTest.java index 6718c5a..c924d41 100644 --- a/src/test/java/net/pterodactylus/sone/template/JavascriptFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/template/JavascriptFilterTest.java @@ -9,8 +9,6 @@ import org.junit.Test; /** * Unit test for {@link JavascriptFilter}. - * - * @author David ‘Bombe’ Roden */ public class JavascriptFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/template/PostAccessorTest.java b/src/test/java/net/pterodactylus/sone/template/PostAccessorTest.java index a6bc381..e60dce9 100644 --- a/src/test/java/net/pterodactylus/sone/template/PostAccessorTest.java +++ b/src/test/java/net/pterodactylus/sone/template/PostAccessorTest.java @@ -22,8 +22,6 @@ import org.junit.Test; /** * Unit test for {@link PostAccessor}. - * - * @author David ‘Bombe’ Roden */ public class PostAccessorTest { diff --git a/src/test/java/net/pterodactylus/sone/test/Dirty.java b/src/test/java/net/pterodactylus/sone/test/Dirty.java index def311a..5d2873f 100644 --- a/src/test/java/net/pterodactylus/sone/test/Dirty.java +++ b/src/test/java/net/pterodactylus/sone/test/Dirty.java @@ -1,18 +1,18 @@ package net.pterodactylus.sone.test; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * This annotation marks test methods that are somehow not good test methods. - * - * @author David ‘Bombe’ Roden + * This annotation marks tests or test methods that are dirty, + * i.e. written in a way no test should ever be written in. */ @Retention(SOURCE) -@Target(METHOD) +@Target(value = { TYPE, METHOD }) public @interface Dirty { String value() default ""; diff --git a/src/test/java/net/pterodactylus/sone/test/Matchers.java b/src/test/java/net/pterodactylus/sone/test/Matchers.java index 08ad611..d04da0f 100644 --- a/src/test/java/net/pterodactylus/sone/test/Matchers.java +++ b/src/test/java/net/pterodactylus/sone/test/Matchers.java @@ -1,5 +1,5 @@ /* - * Sone - Matchers.java - Copyright © 2013–2016 David Roden + * Sone - Matchers.java - Copyright © 2013–2019 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 @@ -35,8 +35,6 @@ import org.hamcrest.TypeSafeMatcher; /** * Matchers used throughout the tests. - * - * @author David ‘Bombe’ Roden */ public class Matchers { diff --git a/src/test/java/net/pterodactylus/sone/test/TestAlbumBuilder.java b/src/test/java/net/pterodactylus/sone/test/TestAlbumBuilder.java index 8871ee3..e091566 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestAlbumBuilder.java +++ b/src/test/java/net/pterodactylus/sone/test/TestAlbumBuilder.java @@ -20,14 +20,12 @@ import org.mockito.stubbing.Answer; /** * {@link AlbumBuilder} that returns a mocked {@link Album}. - * - * @author David ‘Bombe’ Roden */ public class TestAlbumBuilder implements AlbumBuilder { private final Album album = mock(Album.class); - private final List albums = new ArrayList(); - private final List images = new ArrayList(); + private final List albums = new ArrayList<>(); + private final List images = new ArrayList<>(); private Album parentAlbum; private String title; private String description; diff --git a/src/test/java/net/pterodactylus/sone/test/TestImageBuilder.java b/src/test/java/net/pterodactylus/sone/test/TestImageBuilder.java index edeeb1a..d571a1a 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestImageBuilder.java +++ b/src/test/java/net/pterodactylus/sone/test/TestImageBuilder.java @@ -10,8 +10,6 @@ import net.pterodactylus.sone.database.ImageBuilder; /** * {@link ImageBuilder} implementation that returns a mocked {@link Image}. - * - * @author David ‘Bombe’ Roden */ public class TestImageBuilder implements ImageBuilder { diff --git a/src/test/java/net/pterodactylus/sone/test/TestPostBuilder.java b/src/test/java/net/pterodactylus/sone/test/TestPostBuilder.java index 1933857..6cb7828 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestPostBuilder.java +++ b/src/test/java/net/pterodactylus/sone/test/TestPostBuilder.java @@ -12,8 +12,6 @@ import net.pterodactylus.sone.database.PostBuilder; /** * {@link PostBuilder} implementation that returns a mocked {@link Post}. - * - * @author David ‘Bombe’ Roden */ public class TestPostBuilder implements PostBuilder { diff --git a/src/test/java/net/pterodactylus/sone/test/TestPostReplyBuilder.java b/src/test/java/net/pterodactylus/sone/test/TestPostReplyBuilder.java index e09e120..a4f7748 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestPostReplyBuilder.java +++ b/src/test/java/net/pterodactylus/sone/test/TestPostReplyBuilder.java @@ -11,8 +11,6 @@ import net.pterodactylus.sone.database.PostReplyBuilder; /** * {@link PostReplyBuilder} that returns a mocked {@link PostReply}. - * - * @author David ‘Bombe’ Roden */ public class TestPostReplyBuilder implements PostReplyBuilder { diff --git a/src/test/java/net/pterodactylus/sone/test/TestUtil.java b/src/test/java/net/pterodactylus/sone/test/TestUtil.java index 8b3160f..745733f 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestUtil.java +++ b/src/test/java/net/pterodactylus/sone/test/TestUtil.java @@ -1,17 +1,20 @@ package net.pterodactylus.sone.test; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import kotlin.Deprecated; +import kotlin.ReplaceWith; + /** * Utilities for testing. - * - * @author David ‘Bombe’ Roden */ public class TestUtil { + @Deprecated(message = "It only checks the given class, not its superclasses.", replaceWith = @ReplaceWith(imports = { "net.pterodactylus.sone.test" }, expression = "setField(`object`, fieldName, value)")) public static void setFinalField(Object object, String fieldName, Object value) { try { Field clientCoreField = object.getClass().getField(fieldName); @@ -20,9 +23,7 @@ public class TestUtil { modifiersField.setAccessible(true); modifiersField.setInt(clientCoreField, clientCoreField.getModifiers() & ~Modifier.FINAL); clientCoreField.set(object, value); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } @@ -32,9 +33,7 @@ public class TestUtil { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); return (T) field.get(object); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } @@ -44,11 +43,17 @@ public class TestUtil { Method method = object.getClass().getDeclaredMethod(methodName, new Class[0]); method.setAccessible(true); return (T) method.invoke(object); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } + } + + public static T createObject(Class clazz, Class[] parameterTypes, Object... arguments) { + try { + Constructor constructor = clazz.getDeclaredConstructor(parameterTypes); + constructor.setAccessible(true); + return constructor.newInstance(arguments); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } diff --git a/src/test/java/net/pterodactylus/sone/test/TestValue.java b/src/test/java/net/pterodactylus/sone/test/TestValue.java index 94ff3c6..6435d16 100644 --- a/src/test/java/net/pterodactylus/sone/test/TestValue.java +++ b/src/test/java/net/pterodactylus/sone/test/TestValue.java @@ -2,6 +2,9 @@ package net.pterodactylus.sone.test; import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.config.Value; @@ -9,30 +12,30 @@ import com.google.common.base.Objects; /** * Simple {@link Value} implementation. - * - * @author David ‘Bombe’ Roden */ public class TestValue implements Value { - private final AtomicReference value = new AtomicReference(); + private final AtomicReference value = new AtomicReference<>(); - public TestValue(T originalValue) { + public TestValue(@Nullable T originalValue) { value.set(originalValue); } @Override + @Nullable public T getValue() throws ConfigurationException { return value.get(); } @Override - public T getValue(T defaultValue) { + @Nullable + public T getValue(@Nullable T defaultValue) { final T realValue = value.get(); return (realValue != null) ? realValue : defaultValue; } @Override - public void setValue(T newValue) throws ConfigurationException { + public void setValue(@Nullable T newValue) throws ConfigurationException { value.set(newValue); } @@ -48,12 +51,14 @@ public class TestValue implements Value { } @Override + @Nonnull public String toString() { return String.valueOf(value.get()); } - public static Value from(T value) { - return new TestValue(value); + @Nonnull + public static Value from(@Nullable T value) { + return new TestValue<>(value); } } diff --git a/src/test/java/net/pterodactylus/sone/text/FreemailPartTest.java b/src/test/java/net/pterodactylus/sone/text/FreemailPartTest.java index 49972df..5ad1e71 100644 --- a/src/test/java/net/pterodactylus/sone/text/FreemailPartTest.java +++ b/src/test/java/net/pterodactylus/sone/text/FreemailPartTest.java @@ -7,8 +7,6 @@ import org.junit.Test; /** * Unit test for {@link FreemailPart}. - * - * @author David ‘Bombe’ Roden */ public class FreemailPartTest { diff --git a/src/test/java/net/pterodactylus/sone/text/PostPartTest.java b/src/test/java/net/pterodactylus/sone/text/PostPartTest.java index 7b4ea19..5292f5f 100644 --- a/src/test/java/net/pterodactylus/sone/text/PostPartTest.java +++ b/src/test/java/net/pterodactylus/sone/text/PostPartTest.java @@ -11,8 +11,6 @@ import org.junit.Test; /** * Unit test for {@link PostPart}. - * - * @author David ‘Bombe’ Roden */ public class PostPartTest { diff --git a/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java b/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java deleted file mode 100644 index 79f1974..0000000 --- a/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Sone - SoneTextParserTest.java - Copyright © 2011–2016 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 . - */ - -package net.pterodactylus.sone.text; - -import static java.lang.String.format; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.notNullValue; - -import java.io.IOException; -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.data.impl.IdOnlySone; -import net.pterodactylus.sone.database.PostProvider; -import net.pterodactylus.sone.database.SoneProvider; - -import com.google.common.base.Optional; -import kotlin.jvm.functions.Function1; -import org.junit.Test; - -/** - * JUnit test case for {@link SoneTextParser}. - * - * @author David ‘Bombe’ Roden - */ -public class SoneTextParserTest { - - private final SoneTextParser soneTextParser = new SoneTextParser(null, null); - - @SuppressWarnings("static-method") - @Test - public void testPlainText() throws IOException { - /* check basic operation. */ - Iterable parts = soneTextParser.parse("Test.", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test.")); - - /* check empty lines at start and end. */ - parts = soneTextParser.parse("\nTest.\n\n", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test.")); - - /* check duplicate empty lines in the text. */ - parts = soneTextParser.parse("\nTest.\n\n\nTest.", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Test.\n\nTest.")); - } - - @Test - public void consecutiveLinesAreSeparatedByLinefeed() { - Iterable parts = soneTextParser.parse("Text.\nText", null); - assertThat("Part Text", convertText(parts), is("Text.\nText")); - } - - @Test - public void freenetLinksHaveTheFreenetPrefixRemoved() { - Iterable parts = soneTextParser.parse("freenet:KSK@gpl.txt", null); - assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")); - } - - @Test - public void onlyTheFirstItemInALineIsPrefixedWithALineBreak() { - Iterable parts = soneTextParser.parse("Text.\nKSK@gpl.txt and KSK@gpl.txt", null); - assertThat("Part Text", convertText(parts), is("Text.\n[KSK@gpl.txt|KSK@gpl.txt|gpl.txt] and [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")); - } - - @Test - public void soneLinkWithTooShortSoneIdIsRenderedAsPlainText() { - Iterable parts = soneTextParser.parse("sone://too-short", null); - assertThat("Part Text", convertText(parts), is("sone://too-short")); - } - - @Test - public void soneLinkIsRenderedCorrectlyIfSoneIsNotPresent() { - SoneTextParser parser = new SoneTextParser(new AbsentSoneProvider(), null); - Iterable parts = parser.parse("sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU", null); - assertThat("Part Text", convertText(parts), is("[Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU]")); - } - - @Test - public void soneAndPostCanBeParsedFromTheSameText() { - SoneTextParser parser = new SoneTextParser(new TestSoneProvider(), new TestPostProvider()); - Iterable parts = parser.parse("Text sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU more text post://f3757817-b45a-497a-803f-9c5aafc10dc6 even more text", null); - assertThat("Part Text", convertText(parts), is("Text [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] more text [Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text] even more text")); - } - - @Test - public void postLinkIsRenderedAsPlainTextIfPostIdIsTooShort() { - Iterable parts = soneTextParser.parse("post://too-short", null); - assertThat("Part Text", convertText(parts), is("post://too-short")); - } - - @Test - public void postLinkIsRenderedCorrectlyIfPostIsPresent() { - SoneTextParser parser = new SoneTextParser(null, new TestPostProvider()); - Iterable parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null); - assertThat("Part Text", convertText(parts), is("[Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text]")); - } - - @Test - public void postLinkIsRenderedAsPlainTextIfPostIsAbsent() { - SoneTextParser parser = new SoneTextParser(null, new AbsentPostProvider()); - Iterable parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null); - assertThat("Part Text", convertText(parts), is("post://f3757817-b45a-497a-803f-9c5aafc10dc6")); - } - - @Test - public void nameOfFreenetLinkDoesNotContainUrlParameters() { - Iterable parts = soneTextParser.parse("KSK@gpl.txt?max-size=12345", null); - assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt?max-size=12345|KSK@gpl.txt|gpl.txt]")); - } - - @Test - public void trailingSlashInFreenetLinkIsRemovedForName() { - Iterable parts = soneTextParser.parse("KSK@gpl.txt/", null); - assertThat("Part Text", convertText(parts), is("[KSK@gpl.txt/|KSK@gpl.txt/|gpl.txt]")); - } - - @Test - public void lastMetaStringOfFreenetLinkIsUsedAsName() { - Iterable parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING", null); - assertThat("Part Text", convertText(parts), is("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|COPYING]")); - } - - @Test - public void freenetLinkWithoutMetaStringsAndDocNameGetsFirstNineCharactersOfKeyAsName() { - Iterable parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null); - assertThat("Part Text", convertText(parts), is("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nm]")); - } - - @Test - public void malformedKeyIsRenderedAsPlainText() { - Iterable parts = soneTextParser.parse("CHK@qM1nmgU", null); - assertThat("Part Text", convertText(parts), is("CHK@qM1nmgU")); - } - - @Test - public void httpsLinkHasItsPathsShortened() { - Iterable parts = soneTextParser.parse("https://test.test/some-long-path/file.txt", null); - assertThat("Part Text", convertText(parts), is("[https://test.test/some-long-path/file.txt|https://test.test/some-long-path/file.txt|test.test/…/file.txt]")); - } - - @Test - public void httpLinksHaveTheirLastSlashRemoved() { - Iterable parts = soneTextParser.parse("http://test.test/test/", null); - assertThat("Part Text", convertText(parts), is("[http://test.test/test/|http://test.test/test/|test.test/…]")); - } - - @Test - public void wwwPrefixIsRemovedForHostnameWithTwoDotsAndNoPath() { - Iterable parts = soneTextParser.parse("http://www.test.test", null); - assertThat("Part Text", convertText(parts), is("[http://www.test.test|http://www.test.test|test.test]")); - } - - @Test - public void wwwPrefixIsRemovedForHostnameWithTwoDotsAndAPath() { - Iterable parts = soneTextParser.parse("http://www.test.test/test.html", null); - assertThat("Part Text", convertText(parts), is("[http://www.test.test/test.html|http://www.test.test/test.html|test.test/test.html]")); - } - - @Test - public void hostnameIsKeptIntactIfNotBeginningWithWww() { - Iterable parts = soneTextParser.parse("http://test.test.test/test.html", null); - assertThat("Part Text", convertText(parts), is("[http://test.test.test/test.html|http://test.test.test/test.html|test.test.test/test.html]")); - } - - @Test - public void hostnameWithOneDotButNoSlashIsKeptIntact() { - Iterable parts = soneTextParser.parse("http://test.test", null); - assertThat("Part Text", convertText(parts), is("[http://test.test|http://test.test|test.test]")); - } - - @Test - public void urlParametersAreRemovedForHttpLinks() { - Iterable parts = soneTextParser.parse("http://test.test?foo=bar", null); - assertThat("Part Text", convertText(parts), is("[http://test.test?foo=bar|http://test.test?foo=bar|test.test]")); - } - - @Test - public void emptyStringIsParsedCorrectly() { - Iterable parts = soneTextParser.parse("", null); - assertThat("Part Text", convertText(parts), is("")); - } - - @Test - public void linksAreParsedInCorrectOrder() { - Iterable parts = soneTextParser.parse("KSK@ CHK@", null); - assertThat("Part Text", convertText(parts), is("KSK@ CHK@")); - } - - @Test - public void invalidSskAndUskLinkIsParsedAsText() { - Iterable parts = soneTextParser.parse("SSK@a USK@a", null); - assertThat("Part Text", convertText(parts), is("SSK@a USK@a")); - } - - @Test - public void sskLinkWithoutContextIsNotTrusted() { - Iterable parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", null); - assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")); - } - - @Test - public void sskLinkWithContextWithoutSoneIsNotTrusted() { - SoneTextParserContext context = new SoneTextParserContext(null); - Iterable parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context); - assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")); - } - - @Test - public void sskLinkWithContextWithDifferentSoneIsNotTrusted() { - SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU")); - Iterable parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context); - assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")); - } - - @Test - public void sskLinkWithContextWithCorrectSoneIsTrusted() { - SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU")); - Iterable parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context); - assertThat("Part Text", convertText(parts), is("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|trusted|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")); - } - - @Test - public void uskLinkWithContextWithCorrectSoneIsTrusted() { - SoneTextParserContext context = new SoneTextParserContext(new IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU")); - Iterable parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0", context); - assertThat("Part Text", convertText(parts), is("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]")); - } - - @SuppressWarnings("static-method") - @Test - public void testKSKLinks() throws IOException { - /* check basic links. */ - Iterable parts = soneTextParser.parse("KSK@gpl.txt", null); - assertThat("Part Text", convertText(parts, FreenetLinkPart.class), is("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")); - - /* check embedded links. */ - parts = soneTextParser.parse("Link is KSK@gpl.txt\u200b.", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, FreenetLinkPart.class), is("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\u200b.")); - - /* check embedded links and line breaks. */ - parts = soneTextParser.parse("Link is KSK@gpl.txt\nKSK@test.dat\n", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, FreenetLinkPart.class), is("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\n[KSK@test.dat|KSK@test.dat|test.dat]")); - } - - @SuppressWarnings({ "synthetic-access", "static-method" }) - @Test - public void testEmptyLinesAndSoneLinks() throws IOException { - SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null); - - /* check basic links. */ - Iterable parts = soneTextParser.parse("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, SonePart.class), is("Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff.")); - } - - @SuppressWarnings({ "synthetic-access", "static-method" }) - @Test - public void testEmpyHttpLinks() throws IOException { - SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null); - - /* check empty http links. */ - Iterable parts = soneTextParser.parse("Some text. Empty link: http:// – nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class), is("Some text. Empty link: http:// – nice!")); - } - - @Test - public void httpLinkWithoutParensEndsAtNextClosingParen() { - Iterable parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc) – nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text (and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]) – nice!")); - } - - @Test - public void uskLinkEndsAtFirstNonNumericNonSlashCharacterAfterVersionNumber() { - Iterable parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0). Nice", null); - assertThat("Part Text", convertText(parts), is("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]). Nice")); - } - - @Test - public void httpLinkWithOpenedAndClosedParensEndsAtNextClosingParen() { - Iterable parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc_(def)) – nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text (and a link: [http://example.sone/abc_(def)|http://example.sone/abc_(def)|example.sone/abc_(def)]) – nice!")); - } - - @Test - public void punctuationIsIgnoredAtEndOfLinkBeforeWhitespace() { - Iterable parts = soneTextParser.parse("Some text and a link: http://example.sone/abc. Nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]. Nice!")); - } - - @Test - public void multiplePunctuationCharactersAreIgnoredAtEndOfLinkBeforeWhitespace() { - Iterable parts = soneTextParser.parse("Some text and a link: http://example.sone/abc... Nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]... Nice!")); - } - - @Test - public void commasAreIgnoredAtEndOfLinkBeforeWhitespace() { - Iterable parts = soneTextParser.parse("Some text and a link: http://example.sone/abc, nice!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc], nice!")); - } - - @Test - public void exclamationMarksAreIgnoredAtEndOfLinkBeforeWhitespace() { - Iterable parts = soneTextParser.parse("A link: http://example.sone/abc!", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]!")); - } - - @Test - public void questionMarksAreIgnoredAtEndOfLinkBeforeWhitespace() { - Iterable parts = soneTextParser.parse("A link: http://example.sone/abc?", null); - assertThat("Part Text", convertText(parts, PlainTextPart.class, LinkPart.class), is("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]?")); - } - - @Test - public void correctFreemailAddressIsLinkedToCorrectly() { - Iterable parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null); - assertThat("Part Text", convertText(parts), is("Mail me at [Freemail|sone|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]!")); - } - - @Test - public void freemailAddressWithInvalidFreemailIdIsParsedAsText() { - Iterable parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!", null); - assertThat("Part Text", convertText(parts), is("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!")); - } - - @Test - public void freemailAddressWithInvalidSizedFreemailIdIsParsedAsText() { - Iterable parts = soneTextParser.parse("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null); - assertThat("Part Text", convertText(parts), is("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!")); - } - - @Test - public void freemailAddressWithoutLocalPartIsParsedAsText() { - Iterable parts = soneTextParser.parse(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null); - assertThat("Part Text", convertText(parts), is(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!")); - } - - @Test - public void correctFreemailAddressIsParsedCorrectly() { - Iterable parts = soneTextParser.parse("sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail", null); - assertThat("Part Text", convertText(parts), is("[Freemail|sone|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]")); - } - - @Test - public void localPartOfFreemailAddressCanContainLettersDigitsMinusDotUnderscore() { - Iterable parts = soneTextParser.parse("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail", null); - assertThat("Part Text", convertText(parts), is("[Freemail|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]")); - } - - /** - * Converts all given {@link Part}s into a string, validating that the - * part’s classes match only the expected classes. - * - * @param parts - * The parts to convert to text - * @param validClasses - * The valid classes; if no classes are given, all classes are - * valid - * @return The converted text - */ - private static String convertText(Iterable parts, Class... validClasses) { - StringBuilder text = new StringBuilder(); - for (Part part : parts) { - assertThat("Part", part, notNullValue()); - if (validClasses.length != 0) { - assertThat("Part’s class", part.getClass(), isIn(validClasses)); - } - if (part instanceof PlainTextPart) { - text.append(((PlainTextPart) part).getText()); - } else if (part instanceof FreenetLinkPart) { - FreenetLinkPart freenetLinkPart = (FreenetLinkPart) part; - text.append('[').append(freenetLinkPart.getLink()).append('|').append(freenetLinkPart.getTrusted() ? "trusted|" : "").append(freenetLinkPart.getTitle()).append('|').append(freenetLinkPart.getText()).append(']'); - } else if (part instanceof FreemailPart) { - FreemailPart freemailPart = (FreemailPart) part; - text.append(format("[Freemail|%s|%s|%s]", freemailPart.getEmailLocalPart(), freemailPart.getFreemailId(), freemailPart.getIdentityId())); - } else if (part instanceof LinkPart) { - LinkPart linkPart = (LinkPart) part; - text.append('[').append(linkPart.getLink()).append('|').append(linkPart.getTitle()).append('|').append(linkPart.getText()).append(']'); - } else if (part instanceof SonePart) { - SonePart sonePart = (SonePart) part; - text.append("[Sone|").append(sonePart.getSone().getId()).append(']'); - } else if (part instanceof PostPart) { - PostPart postPart = (PostPart) part; - text.append("[Post|").append(postPart.getPost().getId()).append("|").append(postPart.getPost().getText()).append("]"); - } - } - return text.toString(); - } - - /** - * Mock Sone provider. - * - * @author David ‘Bombe’ Roden - */ - private static class TestSoneProvider implements SoneProvider { - - @Nonnull - @Override - public Function1 getSoneLoader() { - return new Function1() { - @Override - public Sone invoke(String soneId) { - return getSone(soneId); - } - }; - } - - @Nullable - @Override - public Sone getSone(final String soneId) { - return new IdOnlySone(soneId); - } - - /** - * {@inheritDocs} - */ - @Override - public Collection getSones() { - return null; - } - - /** - * {@inheritDocs} - */ - @Override - public Collection getLocalSones() { - return null; - } - - /** - * {@inheritDocs} - */ - @Override - public Collection getRemoteSones() { - return null; - } - - } - - private static class AbsentSoneProvider extends TestSoneProvider { - - @Override - public Sone getSone(String soneId) { - return null; - } - - } - - private static class TestPostProvider implements PostProvider { - - @Nullable - @Override - public Post getPost(@Nonnull final String postId) { - return new Post() { - @Override - public String getId() { - return postId; - } - - @Override - public boolean isLoaded() { - return false; - } - - @Override - public Sone getSone() { - return null; - } - - @Override - public Optional getRecipientId() { - return null; - } - - @Override - public Optional getRecipient() { - return null; - } - - @Override - public long getTime() { - return 0; - } - - @Override - public String getText() { - return "text"; - } - - @Override - public boolean isKnown() { - return false; - } - - @Override - public Post setKnown(boolean known) { - return null; - } - }; - } - - @Override - public Collection getPosts(String soneId) { - return null; - } - - @Override - public Collection getDirectedPosts(String recipientId) { - return null; - } - - } - - private static class AbsentPostProvider extends TestPostProvider { - - @Nullable - @Override - public Post getPost(@Nonnull String postId) { - return null; - } - - } - -} diff --git a/src/test/java/net/pterodactylus/sone/text/TextFilterTest.java b/src/test/java/net/pterodactylus/sone/text/TextFilterTest.java index 1076a8a..35623a7 100644 --- a/src/test/java/net/pterodactylus/sone/text/TextFilterTest.java +++ b/src/test/java/net/pterodactylus/sone/text/TextFilterTest.java @@ -9,8 +9,6 @@ import org.junit.Test; /** * JUnit test for {@link TextFilter}. - * - * @author David ‘Bombe’ Roden */ public class TextFilterTest { diff --git a/src/test/java/net/pterodactylus/sone/utils/DefaultOptionTest.java b/src/test/java/net/pterodactylus/sone/utils/DefaultOptionTest.java index 065e1d4..3c82c40 100644 --- a/src/test/java/net/pterodactylus/sone/utils/DefaultOptionTest.java +++ b/src/test/java/net/pterodactylus/sone/utils/DefaultOptionTest.java @@ -11,8 +11,6 @@ import org.junit.Test; /** * Unit test for {@link DefaultOption}. - * - * @author David ‘Bombe’ Roden */ public class DefaultOptionTest { @@ -27,19 +25,19 @@ public class DefaultOptionTest { @Test public void defaultOptionReturnsDefaultValueWhenUnset() { - DefaultOption defaultOption = new DefaultOption(defaultValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue); assertThat(defaultOption.get(), is(defaultValue)); } @Test public void defaultOptionReturnsNullForRealWhenUnset() { - DefaultOption defaultOption = new DefaultOption(defaultValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue); assertThat(defaultOption.getReal(), nullValue()); } @Test public void defaultOptionWillReturnSetValue() { - DefaultOption defaultOption = new DefaultOption(defaultValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue); Object newValue = new Object(); defaultOption.set(newValue); assertThat(defaultOption.get(), is(newValue)); @@ -47,40 +45,40 @@ public class DefaultOptionTest { @Test public void defaultOptionWithValidatorAcceptsValidValues() { - DefaultOption defaultOption = new DefaultOption(defaultValue, matchesAcceptedValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue, matchesAcceptedValue); defaultOption.set(acceptedValue); assertThat(defaultOption.get(), is(acceptedValue)); } @Test(expected = IllegalArgumentException.class) public void defaultOptionWithValidatorRejectsInvalidValues() { - DefaultOption defaultOption = new DefaultOption(defaultValue, matchesAcceptedValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue, matchesAcceptedValue); defaultOption.set(new Object()); } @Test public void defaultOptionValidatesObjectsCorrectly() { - DefaultOption defaultOption = new DefaultOption(defaultValue, matchesAcceptedValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue, matchesAcceptedValue); assertThat(defaultOption.validate(acceptedValue), is(true)); assertThat(defaultOption.validate(new Object()), is(false)); } @Test public void settingToNullWillRestoreDefaultValue() { - DefaultOption defaultOption = new DefaultOption(defaultValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue); defaultOption.set(null); assertThat(defaultOption.get(), is(defaultValue)); } @Test public void validateWithoutValidatorWillValidateNull() { - DefaultOption defaultOption = new DefaultOption(defaultValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue); assertThat(defaultOption.validate(null), is(true)); } @Test public void validateWithValidatorWillValidateNull() { - DefaultOption defaultOption = new DefaultOption(defaultValue, matchesAcceptedValue); + DefaultOption defaultOption = new DefaultOption<>(defaultValue, matchesAcceptedValue); assertThat(defaultOption.validate(null), is(true)); } diff --git a/src/test/java/net/pterodactylus/sone/utils/IntegerRangePredicateTest.java b/src/test/java/net/pterodactylus/sone/utils/IntegerRangePredicateTest.java index 687afa3..2bea3f7 100644 --- a/src/test/java/net/pterodactylus/sone/utils/IntegerRangePredicateTest.java +++ b/src/test/java/net/pterodactylus/sone/utils/IntegerRangePredicateTest.java @@ -10,8 +10,6 @@ import org.junit.Test; /** * Unit test for {@link IntegerRangePredicate}. - * - * @author David ‘Bombe’ Roden */ public class IntegerRangePredicateTest { diff --git a/src/test/java/net/pterodactylus/sone/utils/NumberParsersTest.java b/src/test/java/net/pterodactylus/sone/utils/NumberParsersTest.java index 00c2263..0cb4367 100644 --- a/src/test/java/net/pterodactylus/sone/utils/NumberParsersTest.java +++ b/src/test/java/net/pterodactylus/sone/utils/NumberParsersTest.java @@ -10,8 +10,6 @@ import org.junit.Test; /** * Unit test for {@link NumberParsers}. - * - * @author David ‘Bombe’ Roden */ public class NumberParsersTest { diff --git a/src/test/java/net/pterodactylus/sone/web/WebTestUtils.java b/src/test/java/net/pterodactylus/sone/web/WebTestUtils.java index d4e7596..11a44a4 100644 --- a/src/test/java/net/pterodactylus/sone/web/WebTestUtils.java +++ b/src/test/java/net/pterodactylus/sone/web/WebTestUtils.java @@ -10,8 +10,6 @@ import org.hamcrest.TypeSafeDiagnosingMatcher; /** * Utilities for testing the web package. - * - * @author David ‘Bombe’ Roden */ public class WebTestUtils { diff --git a/src/test/java/net/pterodactylus/sone/web/page/FreenetRequestTest.java b/src/test/java/net/pterodactylus/sone/web/page/FreenetRequestTest.java deleted file mode 100644 index ac01e51..0000000 --- a/src/test/java/net/pterodactylus/sone/web/page/FreenetRequestTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.pterodactylus.sone.web.page; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.mockito.Mockito.mock; - -import java.net.URI; -import java.net.URISyntaxException; - -import net.pterodactylus.util.web.Method; - -import freenet.clients.http.ToadletContext; -import freenet.support.api.HTTPRequest; - -import org.junit.Test; - -/** - * Unit test for {@link FreenetRequest}. - * - * @author David ‘Bombe’ Roden - */ -public class FreenetRequestTest { - - private final URI uri = new URI("."); - private final Method method = Method.GET; - private final HTTPRequest httpRequest = mock(HTTPRequest.class); - private final ToadletContext toadletContext = mock(ToadletContext.class); - private final FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext); - - @SuppressWarnings("unused") - public FreenetRequestTest() throws URISyntaxException { - } - - @Test - public void uriIsRetainedCorrectly() { - assertThat(request.getUri(), is(uri)); - } - - @Test - public void methodIsRetainedCorrectly() { - assertThat(request.getMethod(), is(method)); - } - - @Test - public void httpRequestIsRetainedCorrectly() { - assertThat(request.getHttpRequest(), is(httpRequest)); - } - - @Test - public void toadletContextIsRetainedCorrectly() { - assertThat(request.getToadletContext(), is(toadletContext)); - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/ElementLoaderTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/ElementLoaderTest.kt index dbb5bcc..77c4c62 100644 --- a/src/test/kotlin/net/pterodactylus/sone/core/ElementLoaderTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/core/ElementLoaderTest.kt @@ -14,7 +14,7 @@ class ElementLoaderTest { @Test fun `default image loader can be loaded by guice`() { val injector = createInjector(bindMock()) - assertThat(injector.getInstance(ElementLoader::class.java), notNullValue()); + assertThat(injector.getInstance(ElementLoader::class.java), notNullValue()) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/core/ImageInserterTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/ImageInserterTest.kt new file mode 100644 index 0000000..39a11dc --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/ImageInserterTest.kt @@ -0,0 +1,63 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.core.FreenetInterface.InsertToken +import net.pterodactylus.sone.core.FreenetInterface.InsertTokenSupplier +import net.pterodactylus.sone.data.Image +import net.pterodactylus.sone.data.TemporaryImage +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.notNullValue +import org.junit.Test +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.doThrow +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +/** + * Unit test for [ImageInserter]. + */ +class ImageInserterTest { + + private val temporaryImage = mock().apply { whenever(id).thenReturn("image-id") } + private val image = mock().apply { whenever(id).thenReturn("image-id") } + private val freenetInterface = mock() + private val insertToken = mock() + private val insertTokenSupplier: InsertTokenSupplier = mock().apply { whenever(apply(any())).thenReturn(insertToken) } + private val imageInserter = ImageInserter(freenetInterface, insertTokenSupplier) + + @Test + fun `inserter inserts image`() { + imageInserter.insertImage(temporaryImage, image) + verify(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken::class.java)) + } + + @Test + fun `exception when inserting image is ignored`() { + doThrow(SoneException::class.java).`when`(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken::class.java)) + imageInserter.insertImage(temporaryImage, image) + verify(freenetInterface).insertImage(eq(temporaryImage), eq(image), any(InsertToken::class.java)) + } + + @Test + fun `cancelling image insert that is not running does nothing`() { + imageInserter.cancelImageInsert(image) + verify(insertToken, never()).cancel() + } + + @Test + fun `cancelling image cancels the insert token`() { + imageInserter.insertImage(temporaryImage, image) + imageInserter.cancelImageInsert(image) + verify(insertToken).cancel() + } + + @Test + fun `image inserter can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt new file mode 100644 index 0000000..199604b --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt @@ -0,0 +1,328 @@ +package net.pterodactylus.sone.core + +import com.google.common.eventbus.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.fcp.FcpInterface.* +import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.* +import net.pterodactylus.sone.fcp.event.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +/** + * Unit test for [Preferences]. + */ +class PreferencesTest { + + private val eventBus = mock() + private val preferences = Preferences(eventBus) + private val eventsCaptor = capture() + + @Test + fun `preferences retain insertion delay`() { + preferences.newInsertionDelay = 15 + assertThat(preferences.insertionDelay, equalTo(15)) + } + + @Test + fun `preferences sends event on setting insertion delay`() { + preferences.newInsertionDelay = 15 + verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()) + assertThat(eventsCaptor.allValues, hasItem(InsertionDelayChangedEvent(15))) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid insertion delay is rejected`() { + preferences.newInsertionDelay = -15 + } + + @Test + fun `no event is sent when invalid insertion delay is set`() { + try { + preferences.newInsertionDelay = -15 + } catch (iae: IllegalArgumentException) { + /* ignore. */ + } + + verify(eventBus, never()).post(any()) + } + + @Test + fun `preferences return default value when insertion delay is set to null`() { + preferences.newInsertionDelay = null + assertThat(preferences.insertionDelay, equalTo(60)) + } + + @Test + fun `preferences start with insertion delay default value`() { + assertThat(preferences.insertionDelay, equalTo(60)) + } + + @Test + fun `preferences retain posts per page`() { + preferences.newPostsPerPage = 15 + assertThat(preferences.postsPerPage, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid posts per page is rejected`() { + preferences.newPostsPerPage = -15 + } + + @Test + fun `preferences return default value when posts per page is set to null`() { + preferences.newPostsPerPage = null + assertThat(preferences.postsPerPage, equalTo(10)) + } + + @Test + fun `preferences start with posts per page default value`() { + assertThat(preferences.postsPerPage, equalTo(10)) + } + + @Test + fun `preferences retain images per page`() { + preferences.newImagesPerPage = 15 + assertThat(preferences.imagesPerPage, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid images per page is rejected`() { + preferences.newImagesPerPage = -15 + } + + @Test + fun `preferences return default value when images per page is set to null`() { + preferences.newImagesPerPage = null + assertThat(preferences.imagesPerPage, equalTo(9)) + } + + @Test + fun `preferences start with images per page default value`() { + assertThat(preferences.imagesPerPage, equalTo(9)) + } + + @Test + fun `preferences retain characters per post`() { + preferences.newCharactersPerPost = 150 + assertThat(preferences.charactersPerPost, equalTo(150)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid characters per post is rejected`() { + preferences.newCharactersPerPost = -15 + } + + @Test + fun `preferences return default value when characters per post is set to null`() { + preferences.newCharactersPerPost = null + assertThat(preferences.charactersPerPost, equalTo(400)) + } + + @Test + fun `preferences start with characters per post default value`() { + assertThat(preferences.charactersPerPost, equalTo(400)) + } + + @Test + fun `preferences retain post cut off length`() { + preferences.newPostCutOffLength = 150 + assertThat(preferences.postCutOffLength, equalTo(150)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid post cut off length is rejected`() { + preferences.newPostCutOffLength = -15 + } + + @Test(expected = IllegalArgumentException::class) + fun `cut off length of minus one is not allowed`() { + preferences.newPostCutOffLength = -1 + } + + @Test + fun `preferences return default value when post cut off length is set to null`() { + preferences.newPostCutOffLength = null + assertThat(preferences.postCutOffLength, equalTo(200)) + } + + @Test + fun `preferences start with post cut off length default value`() { + assertThat(preferences.postCutOffLength, equalTo(200)) + } + + @Test + fun `preferences retain require full access of true`() { + preferences.newRequireFullAccess = true + assertThat(preferences.requireFullAccess, equalTo(true)) + } + + @Test + fun `preferences retain require full access of false`() { + preferences.newRequireFullAccess = false + assertThat(preferences.requireFullAccess, equalTo(false)) + } + + @Test + fun `preferences return default value when require full access is set to null`() { + preferences.newRequireFullAccess = null + assertThat(preferences.requireFullAccess, equalTo(false)) + } + + @Test + fun `preferences start with require full access default value`() { + assertThat(preferences.requireFullAccess, equalTo(false)) + } + + @Test + fun `preferences retain positive trust`() { + preferences.newPositiveTrust = 15 + assertThat(preferences.positiveTrust, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid positive trust is rejected`() { + preferences.newPositiveTrust = -15 + } + + @Test + fun `preferences return default value when positive trust is set to null`() { + preferences.newPositiveTrust = null + assertThat(preferences.positiveTrust, equalTo(75)) + } + + @Test + fun `preferences start with positive trust default value`() { + assertThat(preferences.positiveTrust, equalTo(75)) + } + + @Test + fun `preferences retain negative trust`() { + preferences.newNegativeTrust = -15 + assertThat(preferences.negativeTrust, equalTo(-15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid negative trust is rejected`() { + preferences.newNegativeTrust = 150 + } + + @Test + fun `preferences return default value when negative trust is set to null`() { + preferences.newNegativeTrust = null + assertThat(preferences.negativeTrust, equalTo(-25)) + } + + @Test + fun `preferences start with negative trust default value`() { + assertThat(preferences.negativeTrust, equalTo(-25)) + } + + @Test + fun `preferences retain trust comment`() { + preferences.newTrustComment = "Trust" + assertThat(preferences.trustComment, equalTo("Trust")) + } + + @Test + fun `preferences return default value when trust comment is set to null`() { + preferences.newTrustComment = null + assertThat(preferences.trustComment, + equalTo("Set from Sone Web Interface")) + } + + @Test + fun `preferences start with trust comment default value`() { + assertThat(preferences.trustComment, + equalTo("Set from Sone Web Interface")) + } + + @Test + fun `preferences retain fcp interface active of true`() { + preferences.newFcpInterfaceActive = true + assertThat(preferences.fcpInterfaceActive, equalTo(true)) + verify(eventBus).post(any(FcpInterfaceActivatedEvent::class.java)) + } + + @Test + fun `preferences retain fcp interface active of false`() { + preferences.newFcpInterfaceActive = false + assertThat(preferences.fcpInterfaceActive, equalTo(false)) + verify(eventBus).post(any(FcpInterfaceDeactivatedEvent::class.java)) + } + + @Test + fun `preferences return default value when fcp interface active is set to null`() { + preferences.newFcpInterfaceActive = null + assertThat(preferences.fcpInterfaceActive, equalTo(false)) + verify(eventBus).post(any(FcpInterfaceDeactivatedEvent::class.java)) + } + + @Test + fun `preferences start with fcp interface active default value`() { + assertThat(preferences.fcpInterfaceActive, equalTo(false)) + } + + @Test + fun `preferences retain fcp full access required of no`() { + preferences.newFcpFullAccessRequired = NO + assertThat(preferences.fcpFullAccessRequired, equalTo(NO)) + verifyFullAccessRequiredChangedEvent(NO) + } + + private fun verifyFullAccessRequiredChangedEvent( + fullAccessRequired: FullAccessRequired) { + verify(eventBus).post(eventsCaptor.capture()) + assertThat(eventsCaptor.value, instanceOf(FullAccessRequiredChanged::class.java)) + assertThat((eventsCaptor.value as FullAccessRequiredChanged).fullAccessRequired, + equalTo(fullAccessRequired)) + } + + @Test + fun `preferences retain fcp full access required of writing`() { + preferences.newFcpFullAccessRequired = WRITING + assertThat(preferences.fcpFullAccessRequired, equalTo(WRITING)) + verifyFullAccessRequiredChangedEvent(WRITING) + } + + @Test + fun `preferences retain fcp full access required of always`() { + preferences.newFcpFullAccessRequired = ALWAYS + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + verifyFullAccessRequiredChangedEvent(ALWAYS) + } + + @Test + fun `preferences return default value when fcp full access required is set to null`() { + preferences.newFcpFullAccessRequired = null + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + verifyFullAccessRequiredChangedEvent(ALWAYS) + } + + @Test + fun `preferences start with fcp full access required default value`() { + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + } + + @Test + fun `setting insertion delay to valid value sends change event`() { + testPreferencesChangedEvent("InsertionDelay", { preferences.newInsertionDelay = it }, 30) + } + + @Test + fun `setting posts per page to valid value sends change event`() { + testPreferencesChangedEvent("PostsPerPage", { preferences.newPostsPerPage = it }, 31) + } + + private fun testPreferencesChangedEvent(name: String, setter: (T) -> Unit, value: T) { + setter(value) + verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()) + assertThat(eventsCaptor.allValues, hasItem(PreferenceChangedEvent(name, value))) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt new file mode 100644 index 0000000..f79d736 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt @@ -0,0 +1,50 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +class SoneComparsisonTest { + + private val oldSone = mock() + private val newSone = mock() + + private val oldPost = mock() + private val removedPost = mock() + private val newPost = mock() + private val oldPostReply = mock() + private val removedPostReply = mock() + private val newPostReply = mock() + + init { + whenever(oldSone.posts).thenReturn(listOf(oldPost, removedPost)) + whenever(newSone.posts).thenReturn(listOf(oldPost, newPost)) + whenever(oldSone.replies).thenReturn(setOf(oldPostReply, removedPostReply)) + whenever(newSone.replies).thenReturn(setOf(oldPostReply, newPostReply)) + } + + private val soneComparison = SoneComparison(oldSone, newSone) + + @Test + fun `new posts are identified correctly`() { + assertThat(soneComparison.newPosts, contains(newPost)) + } + + @Test + fun `removed posts are identified correctly`() { + assertThat(soneComparison.removedPosts, contains(removedPost)) + } + + @Test + fun `new post replies are identified correctly`() { + assertThat(soneComparison.newPostReplies, contains(newPostReply)) + } + + @Test + fun `removed post replies are identified correctly`() { + assertThat(soneComparison.removedPostReplies, contains(removedPostReply)) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessorTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessorTest.kt new file mode 100644 index 0000000..9e7c71e --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessorTest.kt @@ -0,0 +1,157 @@ +package net.pterodactylus.sone.core + +import com.google.common.eventbus.EventBus +import net.pterodactylus.sone.core.event.NewPostFoundEvent +import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent +import net.pterodactylus.sone.core.event.PostRemovedEvent +import net.pterodactylus.sone.core.event.PostReplyRemovedEvent +import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.database.Database +import net.pterodactylus.sone.test.argumentCaptor +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isProvidedByMock +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.containsInAnyOrder +import org.hamcrest.Matchers.not +import org.hamcrest.Matchers.notNullValue +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.any +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +/** + * Unit test for all [UpdatedSoneProcessor] implementations. + */ +class UpdatedSoneProcessorTest { + + private val database = mock() + private val eventBus = mock() + private val updatedSoneProcessor = DefaultUpdateSoneProcessor(database, eventBus) + private val storedSone = mock() + private val newSone = mock() + private val posts = listOf(mock(), mock(), mock()) + private val postReplies = listOf(mock(), mock(), mock()) + + private val events = argumentCaptor() + + @Before + fun setupPostsAndReplies() { + posts.forEachIndexed { index, post -> whenever(post.time).thenReturn((index + 1) * 1000L + 100) } + postReplies.forEachIndexed { index, postReply -> whenever(postReply.time).thenReturn((index + 1) * 1000L + 200) } + } + + @Before + fun setupSones() { + whenever(storedSone.time).thenReturn(1000L) + whenever(storedSone.posts).thenReturn(posts.slice(0..1)) + whenever(storedSone.replies).thenReturn(postReplies.slice(0..1).toSet()) + whenever(newSone.id).thenReturn("sone") + whenever(newSone.time).thenReturn(2000L) + whenever(newSone.posts).thenReturn(posts.slice(1..2)) + whenever(newSone.replies).thenReturn(postReplies.slice(1..2).toSet()) + } + + @Before + fun setupDatabase() { + whenever(database.getSone("sone")).thenReturn(storedSone) + whenever(database.getFollowingTime("sone")).thenReturn(500L) + } + + @Test + fun `updated Sone processor emits no event if no stored sone exists`() { + whenever(database.getSone("sone")).thenReturn(null) + updatedSoneProcessor.updateSone(newSone) + verify(eventBus, never()).post(any()) + } + + @Test + fun `updated Sone processor emits no event if new Sone is older than stored Sone`() { + whenever(newSone.time).thenReturn(500L) + updatedSoneProcessor.updateSone(newSone) + verify(eventBus, never()).post(any()) + } + + @Test + fun `updated Sone processor emits correct events when new Sone is newer`() { + updatedSoneProcessor.updateSone(newSone) + verify(eventBus, times(4)).post(events.capture()) + assertThat(events.allValues, containsInAnyOrder( + NewPostFoundEvent(posts[2]), + PostRemovedEvent(posts[0]), + NewPostReplyFoundEvent(postReplies[2]), + PostReplyRemovedEvent(postReplies[0]) + )) + } + + @Test + fun `updated Sone processor does not mark new post as known if sone was not followed after post`() { + updatedSoneProcessor.updateSone(newSone) + verify(posts[2], never()).isKnown = true + } + + @Test + fun `updated Sone processor does not mark new posts as known if Sone is not followed`() { + whenever(database.getFollowingTime("sone")).thenReturn(null) + updatedSoneProcessor.updateSone(newSone) + posts.forEach { verify(it, never()).isKnown = true } + } + + @Test + fun `updated Sone processor marks new post as known if sone was followed after post`() { + whenever(database.getFollowingTime("sone")).thenReturn(3500L) + updatedSoneProcessor.updateSone(newSone) + verify(posts[2]).isKnown = true + } + + @Test + fun `updated Sone processor does not emit event for post if it is already known`() { + whenever(posts[2].isKnown).thenReturn(true) + updatedSoneProcessor.updateSone(newSone) + verify(eventBus, atLeastOnce()).post(events.capture()) + assertThat(events.allValues, not(contains(NewPostFoundEvent(posts[2])))) + } + + @Test + fun `updated Sone processor does not mark new reply as known if sone was not followed after reply`() { + updatedSoneProcessor.updateSone(newSone) + verify(postReplies[2], never()).isKnown = true + } + + @Test + fun `updated Sone processor marks new reply as known if sone was followed after reply`() { + whenever(database.getFollowingTime("sone")).thenReturn(3500L) + updatedSoneProcessor.updateSone(newSone) + verify(postReplies[2]).isKnown = true + } + + @Test + fun `updated Sone processor does not emit event for reply if it is already known`() { + whenever(postReplies[2].isKnown).thenReturn(true) + updatedSoneProcessor.updateSone(newSone) + verify(eventBus, atLeastOnce()).post(events.capture()) + assertThat(events.allValues, not(contains(NewPostReplyFoundEvent(postReplies[2])))) + } + + @Test + fun `updated sone processor stores sone in database`() { + updatedSoneProcessor.updateSone(newSone) + verify(database).storeSone(newSone) + } + + @Test + fun `default updated Sone processor can be created by dependency injection`() { + assertThat(baseInjector.createChildInjector( + Database::class.isProvidedByMock() + ).getInstance(), notNullValue()) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/data/ProfileTest.kt b/src/test/kotlin/net/pterodactylus/sone/data/ProfileTest.kt new file mode 100644 index 0000000..54ba0e0 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/data/ProfileTest.kt @@ -0,0 +1,91 @@ +package net.pterodactylus.sone.data + +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +/** + * Unit test for [Profile]. + */ +class ProfileTest { + + private val sone = mock() + private val profile = Profile(sone) + + @Test + fun `first name is initialized with null`() { + assertThat(profile.firstName, nullValue()) + } + + @Test + fun `setting first name to value will set it to value`() { + profile.firstName = "first name" + assertThat(profile.firstName, equalTo("first name")) + } + + @Test + fun `setting first name to null will set it to null`() { + profile.firstName = null + assertThat(profile.firstName, nullValue()) + } + + @Test + fun `setting first name to empty string will set it to null`() { + profile.firstName = "" + assertThat(profile.firstName, nullValue()) + } + + @Test + fun `middle name is initialized with null`() { + assertThat(profile.middleName, nullValue()) + } + + @Test + fun `setting middle name to value will set it to value`() { + profile.middleName = "middle name" + assertThat(profile.middleName, equalTo("middle name")) + } + + @Test + fun `setting middle name to null will set it to null`() { + profile.middleName = null + assertThat(profile.middleName, nullValue()) + } + + @Test + fun `setting middle name to empty string will set it to null`() { + profile.middleName = "" + assertThat(profile.middleName, nullValue()) + } + + @Test + fun `last name is initialized with null`() { + assertThat(profile.lastName, nullValue()) + } + + @Test + fun `setting last name to value will set it to value`() { + profile.lastName = "last name" + assertThat(profile.lastName, equalTo("last name")) + } + + @Test + fun `setting last name to null will set it to null`() { + profile.lastName = null + assertThat(profile.lastName, nullValue()) + } + + @Test + fun `setting last name to empty string will set it to null`() { + profile.lastName = "" + assertThat(profile.lastName, nullValue()) + } + + @Test + fun `new fields are initialized with an empty string`() { + val newField = profile.addField("testField") + assertThat(newField.value, equalTo("")) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.kt b/src/test/kotlin/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.kt new file mode 100644 index 0000000..6f8d5d1 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/database/memory/ConfigurationLoaderTest.kt @@ -0,0 +1,122 @@ +package net.pterodactylus.sone.database.memory + +import net.pterodactylus.sone.test.TestValue.from +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.util.config.Configuration +import net.pterodactylus.util.config.Value +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.containsInAnyOrder +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.nullValue +import org.junit.Test + +/** + * Unit test for [ConfigurationLoader]. + */ +class ConfigurationLoaderTest { + + private val configuration = mock() + private val configurationLoader = ConfigurationLoader(configuration) + + private fun setupStringValue(attribute: String, value: String? = null): Value = + from(value).apply { + whenever(configuration.getStringValue(attribute)).thenReturn(this) + } + + private fun setupLongValue(attribute: String, value: Long? = null): Value = + from(value).apply { + whenever(configuration.getLongValue(attribute)).thenReturn(this) + } + + @Test + fun `loader can load known posts`() { + setupStringValue("KnownPosts/0/ID", "Post2") + setupStringValue("KnownPosts/1/ID", "Post1") + setupStringValue("KnownPosts/2/ID") + val knownPosts = configurationLoader.loadKnownPosts() + assertThat(knownPosts, containsInAnyOrder("Post1", "Post2")) + } + + @Test + fun `loader can load known post replies`() { + setupStringValue("KnownReplies/0/ID", "PostReply2") + setupStringValue("KnownReplies/1/ID", "PostReply1") + setupStringValue("KnownReplies/2/ID") + val knownPosts = configurationLoader.loadKnownPostReplies() + assertThat(knownPosts, containsInAnyOrder("PostReply1", "PostReply2")) + } + + @Test + fun `loader can load bookmarked posts`() { + setupStringValue("Bookmarks/Post/0/ID", "Post2") + setupStringValue("Bookmarks/Post/1/ID", "Post1") + setupStringValue("Bookmarks/Post/2/ID") + val knownPosts = configurationLoader.loadBookmarkedPosts() + assertThat(knownPosts, containsInAnyOrder("Post1", "Post2")) + } + + @Test + fun `loader can save bookmarked posts`() { + val post1 = setupStringValue("Bookmarks/Post/0/ID") + val post2 = setupStringValue("Bookmarks/Post/1/ID") + val post3 = setupStringValue("Bookmarks/Post/2/ID") + val originalPosts = setOf("Post1", "Post2") + configurationLoader.saveBookmarkedPosts(originalPosts) + val extractedPosts = setOf(post1.value, post2.value) + assertThat(extractedPosts, containsInAnyOrder("Post1", "Post2")) + assertThat(post3.value, nullValue()) + } + + @Test + fun `loader can load Sone following times`() { + setupStringValue("SoneFollowingTimes/0/Sone", "Sone1") + setupLongValue("SoneFollowingTimes/0/Time", 1000L) + setupStringValue("SoneFollowingTimes/1/Sone", "Sone2") + setupLongValue("SoneFollowingTimes/1/Time", 2000L) + setupStringValue("SoneFollowingTimes/2/Sone") + assertThat(configurationLoader.getSoneFollowingTime("Sone1"), equalTo(1000L)) + assertThat(configurationLoader.getSoneFollowingTime("Sone2"), equalTo(2000L)) + assertThat(configurationLoader.getSoneFollowingTime("Sone3"), nullValue()) + } + + @Test + fun `loader can overwrite existing Sone following time`() { + val sone1Id = setupStringValue("SoneFollowingTimes/0/Sone", "Sone1") + val sone1Time = setupLongValue("SoneFollowingTimes/0/Time", 1000L) + val sone2Id = setupStringValue("SoneFollowingTimes/1/Sone", "Sone2") + val sone2Time = setupLongValue("SoneFollowingTimes/1/Time", 2000L) + setupStringValue("SoneFollowingTimes/2/Sone") + configurationLoader.setSoneFollowingTime("Sone1", 3000L) + assertThat(listOf(sone1Id.value to sone1Time.value, sone2Id.value to sone2Time.value), containsInAnyOrder>( + "Sone1" to 3000L, + "Sone2" to 2000L + )) + } + + @Test + fun `loader can remove Sone following time`() { + val sone1Id = setupStringValue("SoneFollowingTimes/0/Sone", "Sone1") + val sone1Time = setupLongValue("SoneFollowingTimes/0/Time", 1000L) + val sone2Id = setupStringValue("SoneFollowingTimes/1/Sone", "Sone2") + val sone2Time = setupLongValue("SoneFollowingTimes/1/Time", 2000L) + setupStringValue("SoneFollowingTimes/2/Sone") + configurationLoader.removeSoneFollowingTime("Sone1") + assertThat(sone1Id.value, equalTo("Sone2")) + assertThat(sone1Time.value, equalTo(2000L)) + assertThat(sone2Id.value, nullValue()) + } + + @Test + fun `sone with missing following time is not loaded`() { + setupStringValue("SoneFollowingTimes/0/Sone", "Sone1") + setupLongValue("SoneFollowingTimes/0/Time", 1000L) + setupStringValue("SoneFollowingTimes/1/Sone", "Sone2") + setupLongValue("SoneFollowingTimes/1/Time") + setupStringValue("SoneFollowingTimes/2/Sone") + assertThat(configurationLoader.getSoneFollowingTime("Sone1"), equalTo(1000L)) + assertThat(configurationLoader.getSoneFollowingTime("Sone2"), nullValue()) + assertThat(configurationLoader.getSoneFollowingTime("Sone3"), nullValue()) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.kt b/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.kt new file mode 100644 index 0000000..1536da4 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.kt @@ -0,0 +1,415 @@ +/* + * Sone - MemoryDatabaseTest.kt - Copyright © 2013–2019 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 . + */ + +package net.pterodactylus.sone.database.memory + +import com.google.common.base.* +import com.google.common.base.Optional.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.impl.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.test.Matchers.* +import net.pterodactylus.util.config.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.* +import org.mockito.invocation.* +import java.util.Arrays.* +import java.util.UUID.* +import kotlin.test.* + +/** + * Tests for [MemoryDatabase]. + */ +class MemoryDatabaseTest { + + private val configuration = mock() + private val memoryDatabase = MemoryDatabase(configuration) + private val sone = mock() + + @BeforeTest + fun setupSone() { + whenever(sone.id).thenReturn(SONE_ID) + } + + @Test + fun `stored sone is made available`() { + storeSone() + assertThat(memoryDatabase.getPost("post1"), isPost("post1", 1000L, "post1", absent())) + assertThat(memoryDatabase.getPost("post2"), isPost("post2", 2000L, "post2", of(RECIPIENT_ID))) + assertThat(memoryDatabase.getPost("post3"), nullValue()) + assertThat(memoryDatabase.getPostReply("reply1"), isPostReply("reply1", "post1", 3000L, "reply1")) + assertThat(memoryDatabase.getPostReply("reply2"), isPostReply("reply2", "post2", 4000L, "reply2")) + assertThat(memoryDatabase.getPostReply("reply3"), isPostReply("reply3", "post1", 5000L, "reply3")) + assertThat(memoryDatabase.getPostReply("reply4"), nullValue()) + assertThat(memoryDatabase.getAlbum("album1"), isAlbum("album1", null, "album1", "album-description1")) + assertThat(memoryDatabase.getAlbum("album2"), isAlbum("album2", null, "album2", "album-description2")) + assertThat(memoryDatabase.getAlbum("album3"), isAlbum("album3", "album1", "album3", "album-description3")) + assertThat(memoryDatabase.getAlbum("album4"), nullValue()) + assertThat(memoryDatabase.getImage("image1"), isImage("image1", 1000L, "KSK@image1", "image1", "image-description1", 16, 9)) + assertThat(memoryDatabase.getImage("image2"), isImage("image2", 2000L, "KSK@image2", "image2", "image-description2", 32, 18)) + assertThat(memoryDatabase.getImage("image3"), isImage("image3", 3000L, "KSK@image3", "image3", "image-description3", 48, 27)) + assertThat(memoryDatabase.getImage("image4"), nullValue()) + } + + private fun storeSone() { + val firstPost = TestPostBuilder().withId("post1") + .from(SONE_ID) + .withTime(1000L) + .withText("post1") + .build() + val secondPost = TestPostBuilder().withId("post2") + .from(SONE_ID) + .withTime(2000L) + .withText("post2") + .to(RECIPIENT_ID) + .build() + val posts = asList(firstPost, secondPost) + whenever(sone.posts).thenReturn(posts) + val firstPostFirstReply = TestPostReplyBuilder().withId("reply1") + .from(SONE_ID) + .to(firstPost.id) + .withTime(3000L) + .withText("reply1") + .build() + val firstPostSecondReply = TestPostReplyBuilder().withId("reply3") + .from(RECIPIENT_ID) + .to(firstPost.id) + .withTime(5000L) + .withText("reply3") + .build() + val secondPostReply = TestPostReplyBuilder().withId("reply2") + .from(SONE_ID) + .to(secondPost.id) + .withTime(4000L) + .withText("reply2") + .build() + val postReplies = setOf(firstPostFirstReply, firstPostSecondReply, secondPostReply) + whenever(sone.replies).thenReturn(postReplies) + val firstAlbum = TestAlbumBuilder().withId("album1") + .by(sone) + .build() + .modify() + .setTitle("album1") + .setDescription("album-description1") + .update() + val secondAlbum = TestAlbumBuilder().withId("album2") + .by(sone) + .build() + .modify() + .setTitle("album2") + .setDescription("album-description2") + .update() + val thirdAlbum = TestAlbumBuilder().withId("album3") + .by(sone) + .build() + .modify() + .setTitle("album3") + .setDescription("album-description3") + .update() + firstAlbum.addAlbum(thirdAlbum) + val rootAlbum = mock() + whenever(rootAlbum.id).thenReturn("root") + whenever(rootAlbum.albums).thenReturn(listOf(firstAlbum, secondAlbum)) + whenever(sone.rootAlbum).thenReturn(rootAlbum) + val firstImage = TestImageBuilder().withId("image1") + .build() + .modify() + .setSone(sone) + .setCreationTime(1000L) + .setKey("KSK@image1") + .setTitle("image1") + .setDescription("image-description1") + .setWidth(16) + .setHeight(9) + .update() + val secondImage = TestImageBuilder().withId("image2") + .build() + .modify() + .setSone(sone) + .setCreationTime(2000L) + .setKey("KSK@image2") + .setTitle("image2") + .setDescription("image-description2") + .setWidth(32) + .setHeight(18) + .update() + val thirdImage = TestImageBuilder().withId("image3") + .build() + .modify() + .setSone(sone) + .setCreationTime(3000L) + .setKey("KSK@image3") + .setTitle("image3") + .setDescription("image-description3") + .setWidth(48) + .setHeight(27) + .update() + firstAlbum.addImage(firstImage) + firstAlbum.addImage(thirdImage) + secondAlbum.addImage(secondImage) + memoryDatabase.storeSone(sone) + } + + @Test + fun `stored and removed sone is not available`() { + storeSone() + memoryDatabase.removeSone(sone) + assertThat(memoryDatabase.sones, empty()) + } + + @Test + fun `post recipients are detected correctly`() { + val postWithRecipient = createPost(of(RECIPIENT_ID)) + memoryDatabase.storePost(postWithRecipient) + val postWithoutRecipient = createPost(absent()) + memoryDatabase.storePost(postWithoutRecipient) + assertThat(memoryDatabase.getDirectedPosts(RECIPIENT_ID), contains(postWithRecipient)) + } + + private fun createPost(recipient: Optional): Post { + val postWithRecipient = mock() + whenever(postWithRecipient.id).thenReturn(randomUUID().toString()) + whenever(postWithRecipient.sone).thenReturn(sone) + whenever(postWithRecipient.recipientId).thenReturn(recipient) + return postWithRecipient + } + + @Test + fun `post replies are managed correctly`() { + val firstPost = createPost(absent()) + val firstPostFirstReply = createPostReply(firstPost, 1000L) + val secondPost = createPost(absent()) + val secondPostFirstReply = createPostReply(secondPost, 1000L) + val secondPostSecondReply = createPostReply(secondPost, 2000L) + memoryDatabase.storePost(firstPost) + memoryDatabase.storePost(secondPost) + memoryDatabase.storePostReply(firstPostFirstReply) + memoryDatabase.storePostReply(secondPostFirstReply) + memoryDatabase.storePostReply(secondPostSecondReply) + assertThat(memoryDatabase.getReplies(firstPost.id), contains(firstPostFirstReply)) + assertThat(memoryDatabase.getReplies(secondPost.id), contains(secondPostFirstReply, secondPostSecondReply)) + } + + private fun createPostReply(post: Post, time: Long): PostReply { + val postReply = mock() + whenever(postReply.id).thenReturn(randomUUID().toString()) + whenever(postReply.time).thenReturn(time) + whenever(postReply.post).thenReturn(of(post)) + val postId = post.id + whenever(postReply.postId).thenReturn(postId) + return postReply + } + + @Test + fun `test basic album functionality`() { + val newAlbum = AlbumImpl(mock()) + assertThat(memoryDatabase.getAlbum(newAlbum.id), nullValue()) + memoryDatabase.storeAlbum(newAlbum) + assertThat(memoryDatabase.getAlbum(newAlbum.id), equalTo(newAlbum)) + memoryDatabase.removeAlbum(newAlbum) + assertThat(memoryDatabase.getAlbum(newAlbum.id), nullValue()) + } + + private fun initializeFriends() { + whenever(configuration.getStringValue("Sone/$SONE_ID/Friends/0/ID")).thenReturn(TestValue.from("Friend1")) + whenever(configuration.getStringValue("Sone/$SONE_ID/Friends/1/ID")).thenReturn(TestValue.from("Friend2")) + whenever(configuration.getStringValue("Sone/$SONE_ID/Friends/2/ID")).thenReturn(TestValue.from(null)) + } + + @Test + fun `friends are returned correctly`() { + initializeFriends() + whenever(sone.isLocal).thenReturn(true) + val friends = memoryDatabase.getFriends(sone) + assertThat(friends, containsInAnyOrder("Friend1", "Friend2")) + } + + @Test + fun `friends are only loaded once from configuration`() { + initializeFriends() + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.getFriends(sone) + memoryDatabase.getFriends(sone) + verify(configuration, times(1)).getStringValue("Sone/$SONE_ID/Friends/0/ID") + } + + @Test + fun `friends are only returned for local sones`() { + val friends = memoryDatabase.getFriends(sone) + assertThat(friends, emptyIterable()) + verify(configuration, never()).getStringValue("Sone/$SONE_ID/Friends/0/ID") + } + + @Test + fun `checking for a friend returns true`() { + initializeFriends() + whenever(sone.isLocal).thenReturn(true) + assertThat(memoryDatabase.isFriend(sone, "Friend1"), equalTo(true)) + } + + @Test + fun `checking for a friend that is not a friend returns false`() { + initializeFriends() + whenever(sone.isLocal).thenReturn(true) + assertThat(memoryDatabase.isFriend(sone, "FriendX"), equalTo(false)) + } + + @Test + fun `checking for a friend of remote sone returns false`() { + initializeFriends() + assertThat(memoryDatabase.isFriend(sone, "Friend1"), equalTo(false)) + } + + private fun prepareConfigurationValues(): Map> = + mutableMapOf>().also { configurationValues -> + whenever(configuration.getStringValue(anyString())).thenAnswer(createAndCacheValue(configurationValues)) + whenever(configuration.getLongValue(anyString())).thenAnswer(createAndCacheValue(configurationValues)) + } + + private fun createAndCacheValue(configurationValues: MutableMap>) = + { invocation: InvocationOnMock -> + configurationValues[invocation[0]] + ?: TestValue.from(null).also { + configurationValues[invocation[0]] = it + } + } + + @Test + fun `friend is added correctly to local sone`() { + val configurationValues = prepareConfigurationValues() + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.addFriend(sone, "Friend1") + assertThat(configurationValues["Sone/$SONE_ID/Friends/0/ID"], equalTo>(TestValue.from("Friend1"))) + assertThat(configurationValues["Sone/$SONE_ID/Friends/1/ID"], equalTo>(TestValue.from(null))) + } + + @Test + fun `friend is not added to remote sone`() { + memoryDatabase.addFriend(sone, "Friend1") + verify(configuration, never()).getStringValue(anyString()) + } + + @Test + fun `friend is removed correctly from local sone`() { + val configurationValues = prepareConfigurationValues() + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.addFriend(sone, "Friend1") + memoryDatabase.removeFriend(sone, "Friend1") + assertThat(configurationValues["Sone/$SONE_ID/Friends/0/ID"], equalTo>(TestValue.from(null))) + assertThat(configurationValues["Sone/$SONE_ID/Friends/1/ID"], equalTo>(TestValue.from(null))) + } + + @Test + fun `configuration is not written when a non-friend is removed`() { + prepareConfigurationValues() + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.removeFriend(sone, "Friend1") + verify(configuration).getStringValue(anyString()) + } + + @Test + fun `sone following time is returned correctly`() { + prepareConfigurationValues() + configuration.getStringValue("SoneFollowingTimes/0/Sone").value = "sone" + configuration.getLongValue("SoneFollowingTimes/0/Time").value = 1000L + assertThat(memoryDatabase.getFollowingTime("sone"), equalTo(1000L)) + } + + @Test + fun `null is returned when sone is not followed`() { + prepareConfigurationValues() + configuration.getStringValue("SoneFollowingTimes/0/Sone").value = "otherSone" + configuration.getLongValue("SoneFollowingTimes/0/Time").value = 1000L + assertThat(memoryDatabase.getFollowingTime("sone"), nullValue()) + } + + @Test + fun `time is stored in configuration when a sone is followed`() { + prepareConfigurationValues() + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.addFriend(sone, "Friend") + assertThat(configuration.getStringValue("SoneFollowingTimes/0/Sone").value, equalTo("Friend")) + assertThat(System.currentTimeMillis() - configuration.getLongValue("SoneFollowingTimes/0/Time").value, lessThan(1000L)) + assertThat(configuration.getStringValue("SoneFollowingTimes/1/Sone").value, nullValue()) + } + + @Test + fun `existing time is not overwritten when a sone is followed`() { + prepareConfigurationValues() + configuration.getStringValue("SoneFollowingTimes/0/Sone").value = "Friend" + configuration.getLongValue("SoneFollowingTimes/0/Time").value = 1000L + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.addFriend(sone, "Friend") + assertThat(configuration.getStringValue("SoneFollowingTimes/0/Sone").value, equalTo("Friend")) + assertThat(configuration.getLongValue("SoneFollowingTimes/0/Time").value, equalTo(1000L)) + assertThat(configuration.getStringValue("SoneFollowingTimes/1/Sone").value, nullValue()) + } + + @Test + fun `unfollowing a sone removes the following time`() { + prepareConfigurationValues() + configuration.getStringValue("Sone/sone/Friends/0/ID").value = "Friend" + configuration.getStringValue("SoneFollowingTimes/0/Sone").value = "Friend" + configuration.getLongValue("SoneFollowingTimes/0/Time").value = 1000L + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.removeFriend(sone, "Friend") + assertThat(configuration.getStringValue("SoneFollowingTimes/0/Sone").value, nullValue()) + } + + @Test + fun `unfollowing a sone does not remove the following time if another local sone follows it`() { + prepareConfigurationValues() + configuration.getStringValue("Sone/sone/Friends/0/ID").value = "Friend" + configuration.getStringValue("Sone/other-sone/Friends/0/ID").value = "Friend" + configuration.getStringValue("SoneFollowingTimes/0/Sone").value = "Friend" + configuration.getLongValue("SoneFollowingTimes/0/Time").value = 1000L + val otherSone = mock() + whenever(otherSone.isLocal).thenReturn(true) + whenever(otherSone.id).thenReturn("other-sone") + memoryDatabase.getFriends(otherSone) + whenever(sone.isLocal).thenReturn(true) + memoryDatabase.removeFriend(sone, "Friend") + assertThat(configuration.getStringValue("SoneFollowingTimes/0/Sone").value, equalTo("Friend")) + assertThat(configuration.getLongValue("SoneFollowingTimes/0/Time").value, equalTo(1000L)) + } + + @Test + fun `marking a post as known saves configuration`() { + prepareConfigurationValues() + val post = mock() + whenever(post.id).thenReturn("post-id") + memoryDatabase.setPostKnown(post, true) + assertThat(configuration.getStringValue("KnownPosts/0/ID").value, equalTo("post-id")) + assertThat(configuration.getStringValue("KnownPosts/1/ID").value, equalTo(null)) + } + + @Test + fun `marking a post reply as known saves configuration`() { + prepareConfigurationValues() + val postReply = mock() + whenever(postReply.id).thenReturn("post-reply-id") + memoryDatabase.setPostReplyKnown(postReply, true) + assertThat(configuration.getStringValue("KnownReplies/0/ID").value, equalTo("post-reply-id")) + assertThat(configuration.getStringValue("KnownReplies/1/ID").value, equalTo(null)) + } + +} + +private const val SONE_ID = "sone" +private const val RECIPIENT_ID = "recipient" diff --git a/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryPostTest.kt b/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryPostTest.kt new file mode 100644 index 0000000..90344e1 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/database/memory/MemoryPostTest.kt @@ -0,0 +1,26 @@ +package net.pterodactylus.sone.database.memory + +import com.google.common.base.Optional.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.util.* + +class MemoryPostTest { + + private val memoryDatabase = mock() + + @Test + fun `memory post returns empty optional for post without recipient`() { + val memoryPost = MemoryPost(memoryDatabase, memoryDatabase, UUID.randomUUID().toString(), "soneId", null, 123, "text") + assertThat(memoryPost.recipient, equalTo(absent())) + } + + @Test + fun `empty optional is returned if recipient is set but non-existent`() { + val memoryPost = MemoryPost(memoryDatabase, memoryDatabase, UUID.randomUUID().toString(), "soneId", "recipientId", 123, "text") + assertThat(memoryPost.recipient, equalTo(absent())) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt index 2d77c6e..29db41c 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt @@ -20,7 +20,7 @@ class CreatePostCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt index a6e69cd..373e3db 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt @@ -1,14 +1,11 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional.of -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [CreateReplyCommand]. @@ -21,7 +18,7 @@ class CreateReplyCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt index 30fc4cb..15173d2 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt @@ -1,14 +1,12 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional.of -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeletePostCommand]. @@ -21,7 +19,7 @@ class DeletePostCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt index 6920a33..ca6ec9d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt @@ -1,14 +1,12 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional.of -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteReplyCommand]. @@ -22,7 +20,7 @@ class DeleteReplyCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetLocalSonesCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetLocalSonesCommandTest.kt index 2a78efc..7fd8db3 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetLocalSonesCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetLocalSonesCommandTest.kt @@ -18,7 +18,7 @@ class GetLocalSonesCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt index 5c76c5b..f8113af 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt @@ -39,7 +39,7 @@ class GetPostCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt index d8ab243..767aa28 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt @@ -31,7 +31,7 @@ class GetPostFeedCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt index acf1824..9f7600a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt @@ -24,7 +24,7 @@ class GetPostsCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt index 79aad1a..9b9ed8b 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt @@ -22,7 +22,7 @@ class GetSoneCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSonesCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSonesCommandTest.kt index 252eae3..10f6501 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSonesCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSonesCommandTest.kt @@ -25,7 +25,7 @@ class GetSonesCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt index 6c7d40c..7041f25 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt @@ -1,23 +1,19 @@ package net.pterodactylus.sone.fcp -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.fcp.FcpException -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.freenet.fcp.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LikePostCommand]. */ class LikePostCommandTest : SoneCommandTest() { - private val post = createPost("PostId", mock(), null, 1000, "Text") + private val post = createPost("PostId", mock(), null, 1000, "Text") override fun createCommand(core: Core) = LikePostCommand(core) @@ -30,7 +26,7 @@ class LikePostCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test @@ -70,7 +66,7 @@ class LikePostCommandTest : SoneCommandTest() { @Test fun `request with valid parameters adds post to liked posts for sone`() { - whenever(core.getLikes(post)).thenReturn(setOf(mock(), mock(), mock())) + whenever(core.getLikes(post)).thenReturn(setOf(mock(), mock(), mock())) parameters += "Post" to "PostId" parameters += "Sone" to "LocalSoneId" val replyParameters = command.execute(parameters).replyParameters diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt index 7b9256a..0d0579a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt @@ -1,24 +1,19 @@ package net.pterodactylus.sone.fcp -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.fcp.FcpException -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.freenet.fcp.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LikeReplyCommand]. */ class LikeReplyCommandTest : SoneCommandTest() { - private val reply = createReply("ReplyId", mock(), mock(), 1000, "Text") + private val reply = createReply("ReplyId", mock(), mock(), 1000, "Text") override fun createCommand(core: Core) = LikeReplyCommand(core) @@ -31,7 +26,7 @@ class LikeReplyCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test @@ -71,7 +66,7 @@ class LikeReplyCommandTest : SoneCommandTest() { @Test fun `request with local sone adds reply id to sone`() { - whenever(core.getLikes(reply)).thenReturn(setOf(mock(), mock(), mock())) + whenever(core.getLikes(reply)).thenReturn(setOf(mock(), mock(), mock())) parameters += "Reply" to "ReplyId" parameters += "Sone" to "LocalSoneId" val replyParameters = command.execute(parameters).replyParameters diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt index 284df69..dea019f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt @@ -24,7 +24,7 @@ class LockSoneCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt index de92612..91eabf5 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt @@ -1,22 +1,15 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional.absent -import freenet.support.SimpleFieldSet -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.fcp.FcpException -import net.pterodactylus.sone.template.SoneAccessor -import net.pterodactylus.sone.test.OneByOneMatcher -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional -import org.junit.Before -import org.junit.Rule -import org.junit.rules.ExpectedException -import org.mockito.ArgumentMatchers.anyString +import freenet.support.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.freenet.fcp.* +import net.pterodactylus.sone.template.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import org.junit.* +import org.junit.rules.* +import org.mockito.ArgumentMatchers.* /** * Base class for Sone FCP command tests. diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt index 77e78b3..f520349 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt @@ -24,7 +24,7 @@ class UnlockSoneCommandTest : SoneCommandTest() { @Test fun `command requires write access`() { - assertThat(command.requiresWriteAccess(), equalTo(true)) + assertThat(command.requiresWriteAccess, equalTo(true)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/VersionCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/VersionCommandTest.kt index e54e7aa..9cc9c21 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/VersionCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/VersionCommandTest.kt @@ -15,7 +15,7 @@ class VersionCommandTest : SoneCommandTest() { @Test fun `command does not require write access`() { - assertThat(command.requiresWriteAccess(), equalTo(false)) + assertThat(command.requiresWriteAccess, equalTo(false)) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/freenet/L10nFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/freenet/L10nFilterTest.kt index 39196c1..66b1ab1 100644 --- a/src/test/kotlin/net/pterodactylus/sone/freenet/L10nFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/freenet/L10nFilterTest.kt @@ -4,7 +4,6 @@ import freenet.l10n.BaseL10n import freenet.l10n.BaseL10n.LANGUAGE.ENGLISH import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.web.WebInterface import net.pterodactylus.util.template.TemplateContext import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo @@ -17,18 +16,12 @@ import org.mockito.ArgumentMatchers.anyString */ class L10nFilterTest { - private val webInterface = mock() - private val filter = L10nFilter(webInterface) - private val templateContext = mock() private val l10n = mock() + private val filter = L10nFilter(l10n) + private val templateContext = mock() private val translations = mutableMapOf() @Before - fun setupWebInterface() { - whenever(webInterface.l10n).thenReturn(l10n) - } - - @Before fun setupL10n() { whenever(l10n.selectedLanguage).thenReturn(ENGLISH) whenever(l10n.getString(anyString())).then { translations[it.arguments[0]] } @@ -61,7 +54,7 @@ class L10nFilterTest { @Test fun `filter does not replace values if there are no parameters`() { translations["data"] = "{link}" - assertThat(filter.format(templateContext, "data", emptyMap()), equalTo("{link}")); + assertThat(filter.format(templateContext, "data", emptyMap()), equalTo("{link}")) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/main/FreenetModuleTest.kt b/src/test/kotlin/net/pterodactylus/sone/main/FreenetModuleTest.kt index d0dc7c4..2f55d52 100644 --- a/src/test/kotlin/net/pterodactylus/sone/main/FreenetModuleTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/main/FreenetModuleTest.kt @@ -1,18 +1,15 @@ package net.pterodactylus.sone.main -import com.google.inject.Guice -import freenet.client.HighLevelSimpleClient -import freenet.clients.http.SessionManager -import freenet.node.Node -import freenet.pluginmanager.PluginRespirator -import net.pterodactylus.sone.test.deepMock -import net.pterodactylus.sone.test.getInstance -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.sameInstance -import org.junit.Test -import org.mockito.Mockito.verify +import com.google.inject.* +import freenet.client.* +import freenet.clients.http.* +import freenet.node.* +import freenet.pluginmanager.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [FreenetModule]. @@ -25,10 +22,12 @@ class FreenetModuleTest { } private val node = pluginRespirator.node!! private val highLevelSimpleClient = pluginRespirator.hlSimpleClient!! + private val toadletContainer: ToadletContainer = pluginRespirator.toadletContainer + private val pageMaker: PageMaker = pluginRespirator.pageMaker private val module = FreenetModule(pluginRespirator) private val injector = Guice.createInjector(module) - private inline fun verifySingletonInstance() { + private inline fun verifySingletonInstance() { val firstInstance = injector.getInstance() val secondInstance = injector.getInstance() assertThat(firstInstance, sameInstance(secondInstance)) @@ -36,7 +35,7 @@ class FreenetModuleTest { @Test fun `plugin respirator is returned correctly`() { - assertThat(injector.getInstance(), sameInstance(pluginRespirator)) + assertThat(injector.getInstance(), sameInstance(pluginRespirator)) } @Test @@ -46,7 +45,7 @@ class FreenetModuleTest { @Test fun `node is returned correctly`() { - assertThat(injector.getInstance(), sameInstance(node)) + assertThat(injector.getInstance(), sameInstance(node)) } @Test @@ -56,7 +55,7 @@ class FreenetModuleTest { @Test fun `high level simply client is returned correctly`() { - assertThat(injector.getInstance(), sameInstance(highLevelSimpleClient)) + assertThat(injector.getInstance(), sameInstance(highLevelSimpleClient)) } @Test @@ -66,7 +65,7 @@ class FreenetModuleTest { @Test fun `session manager is returned correctly`() { - assertThat(injector.getInstance(), sameInstance(sessionManager)) + assertThat(injector.getInstance(), sameInstance(sessionManager)) } @Test @@ -75,4 +74,24 @@ class FreenetModuleTest { verify(pluginRespirator).getSessionManager("Sone") } + @Test + fun `toadlet container is returned correctly`() { + assertThat(injector.getInstance(), sameInstance(toadletContainer)) + } + + @Test + fun `toadlet container is returned as singleten`() { + verifySingletonInstance() + } + + @Test + fun `page maker is returned correctly`() { + assertThat(injector.getInstance(), sameInstance(pageMaker)) + } + + @Test + fun `page maker is returned as singleten`() { + verifySingletonInstance() + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/main/SoneModuleCreatorTest.kt b/src/test/kotlin/net/pterodactylus/sone/main/SoneModuleCreatorTest.kt new file mode 100644 index 0000000..0286032 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/main/SoneModuleCreatorTest.kt @@ -0,0 +1,176 @@ +package net.pterodactylus.sone.main + +import com.google.common.base.* +import com.google.common.eventbus.* +import com.google.inject.* +import com.google.inject.name.Names.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.database.memory.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.util.config.* +import net.pterodactylus.util.version.Version +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.io.* +import java.util.concurrent.atomic.* + +class SoneModuleCreatorTest { + + private val currentDir: File = File(".") + private val pluginVersion = Version("", 0, 1, 2) + private val pluginYear = 2019 + private val pluginHomepage = "home://page" + private val sonePlugin = mock().apply { + whenever(version).thenReturn(pluginVersion.toString()) + whenever(year).thenReturn(pluginYear) + whenever(homepage).thenReturn(pluginHomepage) + } + + @After + fun removePropertiesFromCurrentDirectory() { + File(currentDir, "sone.properties").delete() + } + + @Test + fun `creator binds configuration when no file is present`() { + File(currentDir, "sone.properties").delete() + assertThat(getInstance(), notNullValue()) + } + + @Test + fun `creator binds first start to true when no file is present`() { + File(currentDir, "sone.properties").delete() + assertThat(getInstance(named("FirstStart")), equalTo(true)) + } + + @Test + fun `config file is created in current directory if not present`() { + File(currentDir, "sone.properties").delete() + val configuration = getInstance() + configuration.save() + assertThat(File(currentDir, "sone.properties").exists(), equalTo(true)) + } + + @Test + fun `creator binds configuration when file is present`() { + File(currentDir, "sone.properties").writeText("Option=old") + assertThat(getInstance().getStringValue("Option").value, equalTo("old")) + } + + @Test + fun `creator binds first start to false when file is present`() { + File(currentDir, "sone.properties").writeText("Option=old") + assertThat(getInstance(named("FirstStart")), equalTo(false)) + } + + @Test + fun `invalid config file leads to new config being created`() { + File(currentDir, "sone.properties").writeText("Option=old\nbroken") + val configuration = getInstance() + assertThat(configuration.getStringValue("Option").getValue(null), nullValue()) + } + + @Test + fun `invalid config file leads to new config being set to true`() { + File(currentDir, "sone.properties").writeText("Option=old\nbroken") + assertThat(getInstance(named("NewConfig")), equalTo(true)) + } + + @Test + fun `valid config file leads to new config being set to false`() { + File(currentDir, "sone.properties").writeText("Option=old") + assertThat(getInstance(named("NewConfig")), equalTo(false)) + } + + @Test + fun `event bus is bound`() { + assertThat(getInstance(), notNullValue()) + } + + @Test + fun `context is bound`() { + assertThat(getInstance().context, equalTo("Sone")) + } + + @Test + fun `optional context is bound`() { + assertThat(getInstance>().get().context, equalTo("Sone")) + } + + @Test + fun `sone plugin is bound`() { + assertThat(getInstance(), sameInstance(sonePlugin)) + } + + @Test + fun `version is bound`() { + assertThat(getInstance(), equalTo(pluginVersion)) + } + + @Test + fun `plugin version is bound`() { + assertThat(getInstance(), equalTo(PluginVersion(pluginVersion.toString()))) + } + + @Test + fun `plugin year is bound`() { + assertThat(getInstance(), equalTo(PluginYear(pluginYear))) + } + + @Test + fun `plugin homepage in bound`() { + assertThat(getInstance(), equalTo(PluginHomepage(pluginHomepage))) + } + + @Test + fun `database is bound correctly`() { + assertThat(getInstance(), instanceOf(MemoryDatabase::class.java)) + } + + @Test + fun `default loader is used without dev options`() { + assertThat(getInstance(), instanceOf(DefaultLoaders::class.java)) + } + + @Test + fun `default loaders are used if no path is given`() { + File(currentDir, "sone.properties").writeText("Developer.LoadFromFilesystem=true") + assertThat(getInstance(), instanceOf(DefaultLoaders::class.java)) + } + + @Test + fun `debug loaders are used if path is given`() { + File(currentDir, "sone.properties").writeText("Developer.LoadFromFilesystem=true\nDeveloper.FilesystemPath=/tmp") + assertThat(getInstance(), instanceOf(DebugLoaders::class.java)) + } + + class TestObject { + val ref: AtomicReference = AtomicReference() + @Subscribe + fun testEvent(event: Any?) { + ref.set(event) + } + } + + @Test + fun `created objects are registered with event bus`() { + val injector = createInjector() + val eventBus: EventBus = getInstance(injector = injector) + val testObject = getInstance(injector = injector) + val event = Any() + eventBus.post(event) + assertThat(testObject.ref.get(), sameInstance(event)) + } + + private fun createInjector(): Injector = SoneModuleCreator() + .createModule(sonePlugin) + .let { Guice.createInjector(it) } + + private inline fun getInstance(annotation: Annotation? = null, injector: Injector = createInjector()): R = + annotation + ?.let { injector.getInstance(Key.get(object : TypeLiteral() {}, it)) } + ?: injector.getInstance(Key.get(object : TypeLiteral() {})) + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/main/SonePluginTest.kt b/src/test/kotlin/net/pterodactylus/sone/main/SonePluginTest.kt new file mode 100644 index 0000000..6d57b9f --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/main/SonePluginTest.kt @@ -0,0 +1,34 @@ +package net.pterodactylus.sone.main + +import freenet.client.async.USKManager +import freenet.l10n.BaseL10n.LANGUAGE.ENGLISH +import freenet.node.Node +import freenet.node.NodeClientCore +import freenet.pluginmanager.PluginRespirator +import net.pterodactylus.sone.test.* +import org.junit.Test + +/** + * Unit test for [SonePlugin]. + */ +class SonePluginTest { + + private val sonePlugin = SonePlugin() + private val pluginRespirator = deepMock() + private val node = deepMock() + private val clientCore = deepMock() + private val uskManager = deepMock() + + init { + setField(node, "clientCore", clientCore) + whenever(pluginRespirator.node).thenReturn(node) + setField(clientCore, "uskManager", uskManager) + } + + @Test + fun `sone plugin can be started`() { + sonePlugin.setLanguage(ENGLISH) + sonePlugin.runPlugin(pluginRespirator) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ImageAccessorTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ImageAccessorTest.kt index eb692ba..f7da592 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/ImageAccessorTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/ImageAccessorTest.kt @@ -17,7 +17,7 @@ class ImageAccessorTest { private val accessor = ImageAccessor() private val album = mock() - private val images = listOf(mock(), mock()) + private val images = listOf(mock(), mock()) @Before fun setupImages() { diff --git a/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt index 07cba3d..8363f6b 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt @@ -1,35 +1,21 @@ package net.pterodactylus.sone.template -import com.google.inject.Guice -import net.pterodactylus.sone.core.LinkedElement -import net.pterodactylus.sone.test.getInstance -import net.pterodactylus.sone.test.isProvidedByMock -import net.pterodactylus.util.template.ClassPathTemplateProvider -import net.pterodactylus.util.template.HtmlFilter -import net.pterodactylus.util.template.TemplateContextFactory -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.notNullValue -import org.hamcrest.Matchers.nullValue -import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import org.junit.Test +import com.google.inject.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.util.template.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.jsoup.* +import org.jsoup.nodes.* +import org.junit.* /** * Unit test for [LinkedElementRenderFilter]. */ class LinkedElementRenderFilterTest { - private val templateContextFactory = TemplateContextFactory() - - init { - templateContextFactory.addFilter("html", HtmlFilter()) - templateContextFactory.addProvider(ClassPathTemplateProvider(LinkedElementRenderFilter::class.java, "/templates/")) - } - - private val filter = LinkedElementRenderFilter(templateContextFactory) + private val filter = LinkedElementRenderFilter() @Test fun `filter returns null for objects that are not linked elements`() { @@ -38,36 +24,36 @@ class LinkedElementRenderFilterTest { @Test fun `filter renders empty span for not loaded elements`() { - val html = filter.format(null, LinkedElement("KSK@gpl.png", loading = true), emptyMap()) as String + val html = filter.format(null, LinkedElement("KSK@gpl.png", loading = true), emptyMap()) as String val spanNode = Jsoup.parseBodyFragment(html).body().child(0) - assertThat(spanNode.nodeName(), `is`("span")) - assertThat(spanNode.attr("class"), `is`("linked-element not-loaded")) - assertThat(spanNode.attr("title"), `is`("KSK@gpl.png")) - assertThat(spanNode.hasAttr("style"), `is`(false)) - assertThat(spanNode.children().isEmpty(), `is`(true)) + assertThat(spanNode.nodeName(), equalTo("span")) + assertThat(spanNode.attr("class"), equalTo("linked-element not-loaded")) + assertThat(spanNode.attr("title"), equalTo("KSK@gpl.png")) + assertThat(spanNode.hasAttr("style"), equalTo(false)) + assertThat(spanNode.children().isEmpty(), equalTo(true)) } @Test fun `filter can render linked images`() { - val html = filter.format(null, LinkedElement("KSK@gpl.png", properties = mapOf("type" to "image")), emptyMap()) as String + val html = filter.format(null, LinkedElement("KSK@gpl.png", properties = mapOf("type" to "image")), emptyMap()) as String val outerSpanNode = Jsoup.parseBodyFragment(html).body().child(0) - assertThat(outerSpanNode.nodeName(), `is`("span")) - assertThat(outerSpanNode.attr("class"), `is`("linked-element loaded")) - assertThat(outerSpanNode.attr("title"), `is`("KSK@gpl.png")) + assertThat(outerSpanNode.nodeName(), equalTo("span")) + assertThat(outerSpanNode.attr("class"), equalTo("linked-element loaded")) + assertThat(outerSpanNode.attr("title"), equalTo("KSK@gpl.png")) val linkNode = outerSpanNode.child(0) - assertThat(linkNode.nodeName(), `is`("a")) - assertThat(linkNode.attr("href"), `is`("/KSK@gpl.png")) + assertThat(linkNode.nodeName(), equalTo("a")) + assertThat(linkNode.attr("href"), equalTo("/KSK@gpl.png")) val innerSpanNode = linkNode.child(0) - assertThat(innerSpanNode.attr("style"), `is`("background-image: url('/KSK@gpl.png')")) + assertThat(innerSpanNode.attr("style"), equalTo("background-image: url('/KSK@gpl.png')")) } @Test fun `filter can render HTML pages`() { - val html = filter.format(null, LinkedElement("KSK@gpl.html", properties = mapOf("type" to "html", "title" to "Page Title", "description" to "This is the description.")), emptyMap()) as String + val html = filter.format(null, LinkedElement("KSK@gpl.html", properties = mapOf("type" to "html", "title" to "Page Title", "description" to "This is the description.")), emptyMap()) as String val outerSpanNode = Jsoup.parseBodyFragment(html).body().child(0) assertThat(outerSpanNode.nodeName(), equalTo("span")) - assertThat(outerSpanNode.attr("class"), `is`("linked-element loaded")) - assertThat(outerSpanNode.attr("title"), `is`("KSK@gpl.html")) + assertThat(outerSpanNode.attr("class"), equalTo("linked-element loaded")) + assertThat(outerSpanNode.attr("title"), equalTo("KSK@gpl.html")) val linkNode = outerSpanNode.child(0) assertThat(linkNode.nodeName(), equalTo("a")) assertThat(linkNode.attr("href"), equalTo("/KSK@gpl.html")) diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ProfileAccessorTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ProfileAccessorTest.kt index 717d3c5..a2c4ad7 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/ProfileAccessorTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/ProfileAccessorTest.kt @@ -61,7 +61,7 @@ class ProfileAccessorTest { @Before fun setupCore() { - whenever(core.getImage(eq("avatar-id"), anyBoolean())).thenReturn(mock()) + whenever(core.getImage(eq("avatar-id"), anyBoolean())).thenReturn(mock()) } diff --git a/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt index 0920280..5592808 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt @@ -1,29 +1,18 @@ package net.pterodactylus.sone.template -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.text.FreemailPart -import net.pterodactylus.sone.text.FreenetLinkPart -import net.pterodactylus.sone.text.LinkPart +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.text.* import net.pterodactylus.sone.text.Part -import net.pterodactylus.sone.text.PlainTextPart -import net.pterodactylus.sone.text.PostPart -import net.pterodactylus.sone.text.SonePart -import net.pterodactylus.util.template.HtmlFilter -import net.pterodactylus.util.template.TemplateContext -import net.pterodactylus.util.template.TemplateContextFactory -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.hamcrest.Matchers.containsInAnyOrder -import org.jsoup.Jsoup -import org.jsoup.nodes.Attribute -import org.jsoup.nodes.Element -import org.junit.Test -import org.mockito.Mockito.`when` -import java.net.URLEncoder +import net.pterodactylus.util.template.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.jsoup.* +import org.jsoup.nodes.* +import org.junit.* +import org.mockito.* +import java.net.* /** * Unit test for [RenderFilter]. @@ -37,22 +26,18 @@ class RenderFilterTest { private const val POST_ID = "37a06250-6775-4b94-86ff-257ba690953c" } - private val core = mock() - private val templateContextFactory = TemplateContextFactory() - private val templateContext: TemplateContext + private val soneProvider = mock() + private val soneTextParser = mock() + private val htmlFilter = HtmlFilter() private val sone = setupSone(SONE_IDENTITY, "Sone", "First") private val parameters = mutableMapOf() - init { - templateContextFactory.addFilter("html", HtmlFilter()) - templateContext = templateContextFactory.createTemplateContext() - } - - private val filter = RenderFilter(core, templateContextFactory) + private val filter = RenderFilter(soneProvider, soneTextParser, htmlFilter) + private val templateContext = TemplateContext() @Test fun `plain text part is rendered correctly`() { - assertThat(renderParts(PlainTextPart("plain text")), `is`("plain text")) + assertThat(renderParts(PlainTextPart("plain text")), equalTo("plain text")) } private fun renderParts(vararg part: Part) = filter.format(templateContext, listOf(*part), parameters) as String @@ -64,13 +49,13 @@ class RenderFilterTest { } private fun verifyLink(linkNode: Element, url: String, cssClass: String, tooltip: String, text: String) { - assertThat(linkNode.nodeName(), `is`("a")) + assertThat(linkNode.nodeName(), equalTo("a")) assertThat>(linkNode.attributes().asList(), containsInAnyOrder( Attribute("href", url), Attribute("class", cssClass), Attribute("title", tooltip) )) - assertThat(linkNode.text(), `is`(text)) + assertThat(linkNode.text(), equalTo(text)) } @Test @@ -96,11 +81,11 @@ class RenderFilterTest { private fun setupSone(identity: String, name: String?, firstName: String): Sone { val sone = mock() - `when`(sone.id).thenReturn(identity) - `when`(sone.profile).thenReturn(Profile(sone)) - `when`(sone.name).thenReturn(name) + whenever(sone.id).thenReturn(identity) + whenever(sone.profile).thenReturn(Profile(sone)) + whenever(sone.name).thenReturn(name) sone.profile.firstName = firstName - `when`(core.getSone(identity)).thenReturn(sone) + whenever(soneProvider.getSone(identity)).thenReturn(sone) return sone } @@ -114,21 +99,24 @@ class RenderFilterTest { @Test fun `post part is cut off correctly when there are spaces`() { val post = setupPost(sone, "1234 678901 345 789012 45678 01.") + whenever(soneTextParser.parse(eq("1234 678901 345 789012 45678 01."), ArgumentMatchers.any())) + .thenReturn(listOf(PlainTextPart("1234 678901 345 789012 45678 01."))) val linkNode = renderParts(PostPart(post)).toLinkNode() verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "1234 678901 345…") } - private fun setupPost(sone: Sone, value: String): Post { - val post = mock() - `when`(post.id).thenReturn(POST_ID) - `when`(post.sone).thenReturn(sone) - `when`(post.text).thenReturn(value) - return post - } + private fun setupPost(sone: Sone, value: String) = + mock().apply { + whenever(id).thenReturn(POST_ID) + whenever(this.sone).thenReturn(this@RenderFilterTest.sone) + whenever(text).thenReturn(value) + } @Test fun `post part is cut off correctly when there are no spaces`() { val post = setupPost(sone, "1234567890123456789012345678901.") + whenever(soneTextParser.parse(eq("1234567890123456789012345678901."), ArgumentMatchers.any())) + .thenReturn(listOf(PlainTextPart("1234567890123456789012345678901."))) val linkNode = renderParts(PostPart(post)).toLinkNode() verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890…") } @@ -136,6 +124,8 @@ class RenderFilterTest { @Test fun `post part shorter than 21 chars is not cut off`() { val post = setupPost(sone, "12345678901234567890") + whenever(soneTextParser.parse(eq("12345678901234567890"), ArgumentMatchers.any())) + .thenReturn(listOf(PlainTextPart("12345678901234567890"))) val linkNode = renderParts(PostPart(post)).toLinkNode() verifyLink(linkNode, "viewPost.html?post=$POST_ID", "in-sone", "First", "12345678901234567890") } @@ -143,7 +133,7 @@ class RenderFilterTest { @Test fun `multiple parts are rendered correctly`() { val parts = arrayOf(PlainTextPart("te"), PlainTextPart("xt")) - assertThat(renderParts(*parts), `is`("text")) + assertThat(renderParts(*parts), equalTo("text")) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ReplyAccessorTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ReplyAccessorTest.kt index f06069b..f8ac06d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/ReplyAccessorTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/ReplyAccessorTest.kt @@ -34,7 +34,7 @@ class ReplyAccessorTest { @Test fun `returns the likes correctly`() { - val sones = setOf(mock(), mock(), mock()) + val sones = setOf(mock(), mock(), mock()) whenever(core.getLikes(reply)).thenReturn(sones) assertThat(accessor.get(templateContext, reply, "likes"), equalTo(sones)) } @@ -74,7 +74,7 @@ class ReplyAccessorTest { @Test fun `return that a reply is loaded if its sone is not null`() { - whenever(reply.sone).thenReturn(mock()) + whenever(reply.sone).thenReturn(mock()) assertThat(accessor.get(templateContext, reply, "loaded"), equalTo(true)) } diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ReplyGroupFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ReplyGroupFilterTest.kt index 4614454..f1ee884 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/ReplyGroupFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/ReplyGroupFilterTest.kt @@ -26,7 +26,7 @@ class ReplyGroupFilterTest { @Before fun setupReplies() { - (0..4).forEach { + repeat(5) { sones += mock() } (0..7).forEach { diff --git a/src/test/kotlin/net/pterodactylus/sone/template/SoneAccessorTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/SoneAccessorTest.kt index 2fe40d4..87cfce0 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/SoneAccessorTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/SoneAccessorTest.kt @@ -128,7 +128,7 @@ class SoneAccessorTest { @Test fun `accessor returns that the sone’s status is not unknown if it is not unknown`() { - whenever(sone.status).thenReturn(mock()) + whenever(sone.status).thenReturn(mock()) assertAccessorReturnValue("unknown", false) } @@ -140,7 +140,7 @@ class SoneAccessorTest { @Test fun `accessor returns that the sone’s status is not idle if it is not idle`() { - whenever(sone.status).thenReturn(mock()) + whenever(sone.status).thenReturn(mock()) assertAccessorReturnValue("idle", false) } @@ -152,7 +152,7 @@ class SoneAccessorTest { @Test fun `accessor returns that the sone’s status is not inserting if it is not inserting`() { - whenever(sone.status).thenReturn(mock()) + whenever(sone.status).thenReturn(mock()) assertAccessorReturnValue("inserting", false) } @@ -164,7 +164,7 @@ class SoneAccessorTest { @Test fun `accessor returns that the sone’s status is not downloading if it is not downloading`() { - whenever(sone.status).thenReturn(mock()) + whenever(sone.status).thenReturn(mock()) assertAccessorReturnValue("downloading", false) } @@ -217,7 +217,7 @@ class SoneAccessorTest { @Test fun `accessor returns all images in the correct order`() { - val images = listOf(mock(), mock(), mock(), mock(), mock()) + val images = listOf(mock(), mock(), mock(), mock(), mock()) val firstAlbum = createAlbum(listOf(), listOf(images[0], images[3])) val secondAlbum = createAlbum(listOf(), listOf(images[1], images[4], images[2])) val rootAlbum = createAlbum(listOf(firstAlbum, secondAlbum), listOf()) @@ -233,7 +233,7 @@ class SoneAccessorTest { @Test fun `accessor returns all albums in the correct order`() { - val albums = listOf(mock(), mock(), mock(), mock(), mock()) + val albums = listOf(mock(), mock(), mock(), mock(), mock()) val rootAlbum = createAlbum(albums, listOf()) whenever(sone.rootAlbum).thenReturn(rootAlbum) assertAccessorReturnValueMatches("albums", contains(*albums.toTypedArray())) diff --git a/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt b/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt index f5f52b8..2fc4a96 100644 --- a/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt +++ b/src/test/kotlin/net/pterodactylus/sone/test/Guice.kt @@ -2,21 +2,26 @@ package net.pterodactylus.sone.test import com.google.inject.Injector import com.google.inject.Module +import com.google.inject.name.* +import org.mockito.* import javax.inject.Provider import kotlin.reflect.KClass -fun KClass.isProvidedBy(instance: T) = Module { it.bind(this.java).toProvider { instance } } +fun KClass.isProvidedBy(instance: T) = Module { it.bind(this.java).toProvider(Provider { instance }) } +fun KClass.withNameIsProvidedBy(instance: T, name: String) = Module { it.bind(this.java).annotatedWith(Names.named(name)).toProvider(Provider { instance }) } fun KClass.isProvidedBy(provider: com.google.inject.Provider) = Module { it.bind(this.java).toProvider(provider) } fun KClass.isProvidedBy(provider: KClass>) = Module { it.bind(this.java).toProvider(provider.java) } -inline fun KClass.isProvidedByMock() = Module { it.bind(this.java).toProvider { mock() } } +inline fun KClass.isProvidedByMock() = Module { it.bind(this.java).toProvider(Provider { mock() }) } +inline fun KClass.isProvidedByDeepMock() = Module { it.bind(this.java).toProvider(Provider { deepMock() }) } inline fun Injector.getInstance() = getInstance(T::class.java)!! fun supply(javaClass: Class): Source = object : Source { override fun fromInstance(instance: T) = Module { it.bind(javaClass).toInstance(instance) } - override fun byInstance(instance: T) = Module { it.bind(javaClass).toProvider { instance } } + override fun byInstance(instance: T) = Module { it.bind(javaClass).toProvider(Provider { instance }) } override fun byProvider(provider: com.google.inject.Provider) = Module { it.bind(javaClass).toProvider(provider) } override fun byProvider(provider: Class>) = Module { it.bind(javaClass).toProvider(provider) } + override fun byMock() = Module { it.bind(javaClass).toInstance(Mockito.mock(javaClass)) } } interface Source { @@ -24,4 +29,5 @@ interface Source { fun byInstance(instance: T): Module fun byProvider(provider: com.google.inject.Provider): Module fun byProvider(provider: Class>): Module + fun byMock(): Module } diff --git a/src/test/kotlin/net/pterodactylus/sone/test/Matchers.kt b/src/test/kotlin/net/pterodactylus/sone/test/Matchers.kt new file mode 100644 index 0000000..c084d35 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/test/Matchers.kt @@ -0,0 +1,21 @@ +package net.pterodactylus.sone.test + +import net.pterodactylus.util.web.* +import org.hamcrest.* + +fun hasHeader(name: String, value: String) = object : TypeSafeDiagnosingMatcher
    () { + override fun matchesSafely(item: Header, mismatchDescription: Description) = + compare(item.name, { it.equals(name, ignoreCase = true) }) { mismatchDescription.appendText("name is ").appendValue(it) } + ?: compare(item.hasValue(value), { it }) { mismatchDescription.appendText("does not have value ").appendValue(value) } + ?: true + + override fun describeTo(description: Description) { + description.appendText("name is ").appendValue(name) + .appendText(", value is ").appendValue(value) + } +} + +fun compare(value: T, comparison: (T) -> Boolean, onError: (T) -> Unit) = + false.takeUnless { comparison(value) } + ?.also { onError(value) } + diff --git a/src/test/kotlin/net/pterodactylus/sone/test/Mockotlin.kt b/src/test/kotlin/net/pterodactylus/sone/test/Mockotlin.kt index c4fd7cb..85b86d5 100644 --- a/src/test/kotlin/net/pterodactylus/sone/test/Mockotlin.kt +++ b/src/test/kotlin/net/pterodactylus/sone/test/Mockotlin.kt @@ -1,8 +1,7 @@ package net.pterodactylus.sone.test import com.google.inject.Module -import org.mockito.ArgumentCaptor -import org.mockito.Mockito +import org.mockito.* import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.OngoingStubbing @@ -18,12 +17,17 @@ inline fun bind(implementation: T): Module = Module { it!!.bind(T::class.java).toInstance(implementation) } inline fun bindMock(): Module = - Module { it!!.bind(T::class.java).toInstance(mock()) } + Module { it!!.bind(T::class.java).toInstance(mock()) } inline fun whenever(methodCall: T) = Mockito.`when`(methodCall)!! -inline fun OngoingStubbing.thenReturnMock(): OngoingStubbing = this.thenReturn(mock()) +inline fun OngoingStubbing.thenReturnMock(): OngoingStubbing = this.thenReturn(mock()) operator fun InvocationOnMock.get(index: Int): T = getArgument(index) inline fun argumentCaptor(): ArgumentCaptor = ArgumentCaptor.forClass(T::class.java)!! + +fun eq(t: T): T { + ArgumentMatchers.eq(t) + return null as T +} diff --git a/src/test/kotlin/net/pterodactylus/sone/test/OneByOneMatcher.kt b/src/test/kotlin/net/pterodactylus/sone/test/OneByOneMatcher.kt index f0cceca..ac6e955 100644 --- a/src/test/kotlin/net/pterodactylus/sone/test/OneByOneMatcher.kt +++ b/src/test/kotlin/net/pterodactylus/sone/test/OneByOneMatcher.kt @@ -9,7 +9,7 @@ class OneByOneMatcher : TypeSafeDiagnosingMatcher() { private val matchers = mutableListOf>() fun expect(description: String, expected: V, actual: (A) -> V) { - matchers += Matcher(expected, actual, description) + matchers += Matcher(expected, actual, description) } override fun describeTo(description: Description) { diff --git a/src/test/kotlin/net/pterodactylus/sone/test/TestUtils.kt b/src/test/kotlin/net/pterodactylus/sone/test/TestUtils.kt new file mode 100644 index 0000000..9996925 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/test/TestUtils.kt @@ -0,0 +1,19 @@ +package net.pterodactylus.sone.test + +import java.lang.reflect.* + +private val modifiers = Field::class.java.getDeclaredField("modifiers").apply { + isAccessible = true +} + +fun setField(instance: Any, name: String, value: Any?) { + generateSequence>(instance.javaClass) { it.superclass } + .flatMap { it.declaredFields.asSequence() } + .filter { it.name == name } + .toList() + .forEach { field -> + field.isAccessible = true + modifiers.setInt(field, field.modifiers and Modifier.FINAL.inv()) + field.set(instance, value) + } +} diff --git a/src/test/kotlin/net/pterodactylus/sone/text/SonePartTest.kt b/src/test/kotlin/net/pterodactylus/sone/text/SonePartTest.kt index 361bd19..31fca48 100644 --- a/src/test/kotlin/net/pterodactylus/sone/text/SonePartTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/text/SonePartTest.kt @@ -16,7 +16,7 @@ class SonePartTest { private val sone = mock() init { - `when`(sone.profile).thenReturn(mock()) + `when`(sone.profile).thenReturn(mock()) `when`(sone.name).thenReturn("sone") } diff --git a/src/test/kotlin/net/pterodactylus/sone/text/SoneTextParserTest.kt b/src/test/kotlin/net/pterodactylus/sone/text/SoneTextParserTest.kt new file mode 100644 index 0000000..b20225a --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/text/SoneTextParserTest.kt @@ -0,0 +1,458 @@ +/* + * Sone - SoneTextParserTest.kt - Copyright © 2011–2019 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 . + */ + +package net.pterodactylus.sone.text + +import com.google.inject.Guice.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.impl.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import kotlin.test.* + +/** + * JUnit test case for [SoneTextParser]. + */ +class SoneTextParserTest { + + private val soneTextParser = SoneTextParser(null, null) + + @Test + fun `basic operation`() { + val parts = soneTextParser.parse("Test.", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test.")) + } + + @Test + fun `empty lines at start and end are stripped`() { + val parts = soneTextParser.parse("\nTest.\n\n", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test.")) + } + + @Test + fun `duplicate empty lines in the text are stripped`() { + val parts = soneTextParser.parse("\nTest.\n\n\nTest.", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Test.\n\nTest.")) + } + + @Test + fun `consecutive lines are separated by linefeed`() { + val parts = soneTextParser.parse("Text.\nText", null) + assertThat("Part Text", convertText(parts), equalTo("Text.\nText")) + } + + @Test + fun `freenet links have the freenet prefix removed`() { + val parts = soneTextParser.parse("freenet:KSK@gpl.txt", null) + assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")) + } + + @Test + fun `only the first item in a line is prefixed with a line break`() { + val parts = soneTextParser.parse("Text.\nKSK@gpl.txt and KSK@gpl.txt", null) + assertThat("Part Text", convertText(parts), equalTo("Text.\n[KSK@gpl.txt|KSK@gpl.txt|gpl.txt] and [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")) + } + + @Test + fun `sone link with too short sone ID is rendered as plain text`() { + val parts = soneTextParser.parse("sone://too-short", null) + assertThat("Part Text", convertText(parts), equalTo("sone://too-short")) + } + + @Test + fun `sone link is rendered correctly if sone is not present`() { + val parser = SoneTextParser(AbsentSoneProvider(), null) + val parts = parser.parse("sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU", null) + assertThat("Part Text", convertText(parts), equalTo("[Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU]")) + } + + @Test + fun `sone and post can be parsed from the same text`() { + val parser = SoneTextParser(TestSoneProvider(), TestPostProvider()) + val parts = parser.parse("Text sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU more text post://f3757817-b45a-497a-803f-9c5aafc10dc6 even more text", null) + assertThat("Part Text", convertText(parts), equalTo("Text [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] more text [Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text] even more text")) + } + + @Test + fun `post link is rendered as plain text if post ID is too short`() { + val parts = soneTextParser.parse("post://too-short", null) + assertThat("Part Text", convertText(parts), equalTo("post://too-short")) + } + + @Test + fun `post link is rendered correctly if post is present`() { + val parser = SoneTextParser(null, TestPostProvider()) + val parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null) + assertThat("Part Text", convertText(parts), equalTo("[Post|f3757817-b45a-497a-803f-9c5aafc10dc6|text]")) + } + + @Test + fun `post link is rendered as plain text if post is absent`() { + val parser = SoneTextParser(null, AbsentPostProvider()) + val parts = parser.parse("post://f3757817-b45a-497a-803f-9c5aafc10dc6", null) + assertThat("Part Text", convertText(parts), equalTo("post://f3757817-b45a-497a-803f-9c5aafc10dc6")) + } + + @Test + fun `name of freenet link does not contain url parameters`() { + val parts = soneTextParser.parse("KSK@gpl.txt?max-size=12345", null) + assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt?max-size=12345|KSK@gpl.txt|gpl.txt]")) + } + + @Test + fun `trailing slash in freenet link is removed for name`() { + val parts = soneTextParser.parse("KSK@gpl.txt/", null) + assertThat("Part Text", convertText(parts), equalTo("[KSK@gpl.txt/|KSK@gpl.txt/|gpl.txt]")) + } + + @Test + fun `last meta string of freenet link is used as name`() { + val parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING", null) + assertThat("Part Text", convertText(parts), equalTo("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/COPYING|COPYING]")) + } + + @Test + fun `freenet link without meta strings and doc name gets first nine characters of key as name`() { + val parts = soneTextParser.parse("CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null) + assertThat("Part Text", convertText(parts), equalTo("[CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|CHK@qM1nm]")) + } + + @Test + fun `malformed key is rendered as plain text`() { + val parts = soneTextParser.parse("CHK@qM1nmgU", null) + assertThat("Part Text", convertText(parts), equalTo("CHK@qM1nmgU")) + } + + @Test + fun `https link has its paths shortened`() { + val parts = soneTextParser.parse("https://test.test/some-long-path/file.txt", null) + assertThat("Part Text", convertText(parts), equalTo("[https://test.test/some-long-path/file.txt|https://test.test/some-long-path/file.txt|test.test/…/file.txt]")) + } + + @Test + fun `http links have their last slash removed`() { + val parts = soneTextParser.parse("http://test.test/test/", null) + assertThat("Part Text", convertText(parts), equalTo("[http://test.test/test/|http://test.test/test/|test.test/…]")) + } + + @Test + fun `www prefix is removed for hostname with two dots and no path`() { + val parts = soneTextParser.parse("http://www.test.test", null) + assertThat("Part Text", convertText(parts), equalTo("[http://www.test.test|http://www.test.test|test.test]")) + } + + @Test + fun `www prefix is removed for hostname with two dots and a path`() { + val parts = soneTextParser.parse("http://www.test.test/test.html", null) + assertThat("Part Text", convertText(parts), equalTo("[http://www.test.test/test.html|http://www.test.test/test.html|test.test/test.html]")) + } + + @Test + fun `hostname is kept intact if not beginning with www`() { + val parts = soneTextParser.parse("http://test.test.test/test.html", null) + assertThat("Part Text", convertText(parts), equalTo("[http://test.test.test/test.html|http://test.test.test/test.html|test.test.test/test.html]")) + } + + @Test + fun `hostname with one dot but no slash is kept intact`() { + val parts = soneTextParser.parse("http://test.test", null) + assertThat("Part Text", convertText(parts), equalTo("[http://test.test|http://test.test|test.test]")) + } + + @Test + fun `url parameters are removed for http links`() { + val parts = soneTextParser.parse("http://test.test?foo=bar", null) + assertThat("Part Text", convertText(parts), equalTo("[http://test.test?foo=bar|http://test.test?foo=bar|test.test]")) + } + + @Test + fun `empty string is parsed correctly`() { + val parts = soneTextParser.parse("", null) + assertThat("Part Text", convertText(parts), equalTo("")) + } + + @Test + fun `links are parsed in correct order`() { + val parts = soneTextParser.parse("KSK@ CHK@", null) + assertThat("Part Text", convertText(parts), equalTo("KSK@ CHK@")) + } + + @Test + fun `invalid ssk and usk link is parsed as text`() { + val parts = soneTextParser.parse("SSK@a USK@a", null) + assertThat("Part Text", convertText(parts), equalTo("SSK@a USK@a")) + } + + @Test + fun `ssk without document name is parsed correctly`() { + val parts = soneTextParser.parse( + "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8", null) + assertThat("Part Text", convertText(parts), + equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|" + + "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8|" + + "SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU]")) + } + + @Test + fun `ssk link without context is not trusted`() { + val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", null) + assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")) + } + + @Test + fun `ssk link with context without sone is not trusted`() { + val context = SoneTextParserContext(null) + val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context) + assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")) + } + + @Test + fun `ssk link with context with different sone is not trusted`() { + val context = SoneTextParserContext(IdOnlySone("DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU")) + val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context) + assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")) + } + + @Test + fun `ssk link with context with correct sone is trusted`() { + val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU")) + val parts = soneTextParser.parse("SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test", context) + assertThat("Part Text", convertText(parts), equalTo("[SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|trusted|SSK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test|test]")) + } + + @Test + fun `usk link with context with correct sone is trusted`() { + val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU")) + val parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0", context) + assertThat("Part Text", convertText(parts), equalTo("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]")) + } + + @Test + fun `usk links with backlinks is parsed correctly`() { + val context = SoneTextParserContext(IdOnlySone("qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU")) + val parts = soneTextParser.parse("USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/../../../USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/78/", context) + assertThat("Part Text", convertText(parts), equalTo("[USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|trusted|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]")) + } + + @Test + fun `test basic ksk links`() { + val parts: Iterable = soneTextParser.parse("KSK@gpl.txt", null) + assertThat("Part Text", convertText(parts, FreenetLinkPart::class.java), equalTo("[KSK@gpl.txt|KSK@gpl.txt|gpl.txt]")) + } + + @Test + fun `embedded ksk links are parsed correctly`() { + val parts = soneTextParser.parse("Link is KSK@gpl.txt\u200b.", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, FreenetLinkPart::class.java), equalTo("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\u200b.")) + } + + @Test + fun `embedded ksk links and line breaks are parsed correctly`() { + val parts = soneTextParser.parse("Link is KSK@gpl.txt\nKSK@test.dat\n", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, FreenetLinkPart::class.java), equalTo("Link is [KSK@gpl.txt|KSK@gpl.txt|gpl.txt]\n[KSK@test.dat|KSK@test.dat|test.dat]")) + } + + @Test + fun `ksk links with backlinks are parsed correctly`() { + val parts = soneTextParser.parse("KSK@gallery/../Sone/imageBrowser.html?album=30c930ee-97cd-11e9-bd44-f3e595768b77", null) + assertThat("Part Text", convertText(parts, FreenetLinkPart::class.java), equalTo("[KSK@gallery|KSK@gallery|gallery]")) + } + + @Test + fun `test empty lines and sone links`() { + val soneTextParser = SoneTextParser(TestSoneProvider(), null) + + /* check basic links. */ + val parts = soneTextParser.parse("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, SonePart::class.java), equalTo("Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff.")) + } + + @Test + fun `test empy http links`() { + val soneTextParser = SoneTextParser(TestSoneProvider(), null) + + /* check empty http links. */ + val parts = soneTextParser.parse("Some text. Empty link: http:// – nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java), equalTo("Some text. Empty link: http:// – nice!")) + } + + @Test + fun `http link without parens ends at next closing paren`() { + val parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc) – nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text (and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]) – nice!")) + } + + @Test + fun `usk link ends at first non numeric non slash character after version number`() { + val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0). Nice", null) + assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]). Nice")) + } + + @Test + fun `usk link with filename shows the filename`() { + val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg). Nice", null) + assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/images/image.jpg|image.jpg]). Nice")) + } + + @Test + fun `usk link without filename but ending in slash shows the path`() { + val parts = soneTextParser.parse("Some link (USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0/). Nice", null) + assertThat("Part Text", convertText(parts), equalTo("Some link ([USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|USK@qM1nmgU-YUnIttmEhqjTl7ifAF3Z6o~5EPwQW03uEQU,aztSUkT-VT1dWvfSUt9YpfyW~Flmf5yXpBnIE~v8sAg,AAMC--8/test/0|test]). Nice")) + } + + @Test + fun `http link with opened and closed parens ends at next closing paren`() { + val parts = soneTextParser.parse("Some text (and a link: http://example.sone/abc_(def)) – nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text (and a link: [http://example.sone/abc_(def)|http://example.sone/abc_(def)|example.sone/abc_(def)]) – nice!")) + } + + @Test + fun `punctuation is ignored at end of link before whitespace`() { + val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc. Nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]. Nice!")) + } + + @Test + fun `multiple punctuation characters are ignored at end of link before whitespace`() { + val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc... Nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]... Nice!")) + } + + @Test + fun `commas are ignored at end of link before whitespace`() { + val parts = soneTextParser.parse("Some text and a link: http://example.sone/abc, nice!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("Some text and a link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc], nice!")) + } + + @Test + fun `exclamation marks are ignored at end of link before whitespace`() { + val parts = soneTextParser.parse("A link: http://example.sone/abc!", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]!")) + } + + @Test + fun `question marks are ignored at end of link before whitespace`() { + val parts = soneTextParser.parse("A link: http://example.sone/abc?", null) + assertThat("Part Text", convertText(parts, PlainTextPart::class.java, LinkPart::class.java), equalTo("A link: [http://example.sone/abc|http://example.sone/abc|example.sone/abc]?")) + } + + @Test + fun `correct freemail address is linked to correctly`() { + val parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null) + assertThat("Part Text", convertText(parts), equalTo("Mail me at [Freemail|sone|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]!")) + } + + @Test + fun `freemail address with invalid freemail id is parsed as text`() { + val parts = soneTextParser.parse("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!", null) + assertThat("Part Text", convertText(parts), equalTo("Mail me at sone@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqr8.freemail!")) + } + + @Test + fun `freemail address with invalid sized freemail id is parsed as text`() { + val parts = soneTextParser.parse("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null) + assertThat("Part Text", convertText(parts), equalTo("Mail me at sone@4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!")) + } + + @Test + fun `freemail address without local part is parsed as text`() { + val parts = soneTextParser.parse(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!", null) + assertThat("Part Text", convertText(parts), equalTo(" @t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail!")) + } + + @Test + fun `local part of freemail address can contain letters digits minus dot underscore`() { + val parts = soneTextParser.parse("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._@t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra.freemail", null) + assertThat("Part Text", convertText(parts), equalTo("[Freemail|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._|t4dlzfdww3xvsnsc6j6gtliox6zaoak7ymkobbmcmdw527ubuqra|nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI]")) + } + + private fun convertText(parts: Iterable, vararg validClasses: Class<*>): String { + if (validClasses.isNotEmpty()) { + assertThat(parts.map { it.javaClass }.distinct() - validClasses.distinct(), empty()) + } + return parts.joinToString("") { part -> + when (part) { + is PlainTextPart -> part.text + is FreenetLinkPart -> "[${part.link}|${if (part.trusted) "trusted|" else ""}${part.title}|${part.text}]" + is FreemailPart -> "[Freemail|${part.emailLocalPart}|${part.freemailId}|${part.identityId}]" + is LinkPart -> "[${part.link}|${part.title}|${part.text}]" + is SonePart -> "[Sone|${part.sone.id}]" + is PostPart -> "[Post|${part.post.id}|${part.post.text}]" + else -> throw NoSuchElementException() + } + } + } + + @Test + fun `parser can be created by guice`() { + val injector = createInjector( + SoneProvider::class.isProvidedByMock(), + PostProvider::class.isProvidedByMock() + ) + assertThat(injector.getInstance(), notNullValue()) + } + + /** + * Mock Sone provider. + */ + private open class TestSoneProvider : SoneProvider { + + override val soneLoader = this::getSone + override val sones: Collection = emptySet() + override val localSones: Collection = emptySet() + override val remoteSones: Collection = emptySet() + + override fun getSone(soneId: String): Sone? = IdOnlySone(soneId) + + } + + private class AbsentSoneProvider : TestSoneProvider() { + + override fun getSone(soneId: String): Sone? = null + + } + + private open class TestPostProvider : PostProvider { + + override fun getPost(postId: String): Post? { + return object : Post { + override val id = postId + override fun isLoaded() = false + override fun getSone() = null + override fun getRecipientId() = null + override fun getRecipient() = null + override fun getTime() = 0L + override fun getText() = "text" + override fun isKnown() = false + override fun setKnown(known: Boolean) = null + } + } + + override fun getPosts(soneId: String) = emptySet() + override fun getDirectedPosts(recipientId: String) = emptySet() + + } + + private class AbsentPostProvider : TestPostProvider() { + + override fun getPost(postId: String): Post? = null + + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/utils/ObjectsTest.kt b/src/test/kotlin/net/pterodactylus/sone/utils/ObjectsTest.kt index 1c2d7f5..9e96bfe 100644 --- a/src/test/kotlin/net/pterodactylus/sone/utils/ObjectsTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/utils/ObjectsTest.kt @@ -1,8 +1,7 @@ package net.pterodactylus.sone.utils import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.empty +import org.hamcrest.Matchers.* import org.junit.Test /** @@ -20,4 +19,26 @@ class ObjectsTest { assertThat(null.asList(), empty()) } + @Test(expected = IllegalArgumentException::class) + fun `exception is thrown for null and true condition`() { + null.throwOnNullIf(true) { IllegalArgumentException() } + } + + @Test + fun `exception is not thrown for null and false condition`() { + assertThat(null.throwOnNullIf(false) { IllegalArgumentException() }, nullValue()) + } + + @Test + fun `exception is not thrown for any and true condition`() { + val any = Any() + assertThat(any.throwOnNullIf(true) { IllegalArgumentException() }, equalTo(any)) + } + + @Test + fun `exception is not thrown for any and false condition`() { + val any = Any() + assertThat(any.throwOnNullIf(false) { IllegalArgumentException() }, equalTo(any)) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/utils/PaginationTest.kt b/src/test/kotlin/net/pterodactylus/sone/utils/PaginationTest.kt index 3ce20ce..d3f063d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/utils/PaginationTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/utils/PaginationTest.kt @@ -12,7 +12,7 @@ import org.junit.Test class PaginationTest { private val items = listOf(1, 2, 3, 4, 5) - private val pagination = Pagination(items, 2) + private val pagination = Pagination(items, 2) @Test fun `pagination can be created from iterable`() { diff --git a/src/test/kotlin/net/pterodactylus/sone/web/AllPagesTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/AllPagesTest.kt new file mode 100644 index 0000000..cf6ab15 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/AllPagesTest.kt @@ -0,0 +1,253 @@ +package net.pterodactylus.sone.web + +import com.google.inject.Guice.createInjector +import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.core.FreenetInterface +import net.pterodactylus.sone.main.PluginHomepage +import net.pterodactylus.sone.main.PluginVersion +import net.pterodactylus.sone.main.PluginYear +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.sone.web.pages.* +import net.pterodactylus.util.template.Template +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers +import org.junit.Test + +/** + * Test for [AllPages]. + */ +class AllPagesTest { + + private val injector by lazy { + baseInjector.createChildInjector( + PluginVersion::class.isProvidedByMock(), + PluginYear::class.isProvidedByMock(), + PluginHomepage::class.isProvidedByMock() + )!! + } + private val allPages by lazy { injector.getInstance() } + + private inline fun instanceOf(): Matcher = Matchers.instanceOf(T::class.java) + + @Test + fun `about page can be injected`() { + assertThat(allPages.aboutPage, instanceOf()) + } + + @Test + fun `bookmark page can be injected`() { + assertThat(allPages.bookmarkPage, instanceOf()) + } + + @Test + fun `bookmarks page can be injected`() { + assertThat(allPages.bookmarksPage, instanceOf()) + } + + @Test + fun `create album page can be injected`() { + assertThat(allPages.createAlbumPage, instanceOf()) + } + + @Test + fun `create post page can be injected`() { + assertThat(allPages.createPostPage, instanceOf()) + } + + @Test + fun `create reply page can be injected`() { + assertThat(allPages.createReplyPage, instanceOf()) + } + + @Test + fun `create sone page can be injected`() { + assertThat(allPages.createSonePage, instanceOf()) + } + + @Test + fun `delete album page can be injected`() { + assertThat(allPages.deleteAlbumPage, instanceOf()) + } + + @Test + fun `delete image page can be injected`() { + assertThat(allPages.deleteImagePage, instanceOf()) + } + + @Test + fun `delete post page can be injected`() { + assertThat(allPages.deletePostPage, instanceOf()) + } + + @Test + fun `delete profile field page can be injected`() { + assertThat(allPages.deleteProfileFieldPage, instanceOf()) + } + + @Test + fun `delete reply page can be injected`() { + assertThat(allPages.deleteReplyPage, instanceOf()) + } + + @Test + fun `delete sone page can be injected`() { + assertThat(allPages.deleteSonePage, instanceOf()) + } + + @Test + fun `dismiss notification page can be injected`() { + assertThat(allPages.dismissNotificationPage, instanceOf()) + } + + @Test + fun `distrust page can be injected`() { + assertThat(allPages.distrustPage, instanceOf()) + } + + @Test + fun `edit album page can be injected`() { + assertThat(allPages.editAlbumPage, instanceOf()) + } + + @Test + fun `edit image page can be injected`() { + assertThat(allPages.editImagePage, instanceOf()) + } + + @Test + fun `edit profile field page can be injected`() { + assertThat(allPages.editProfileFieldPage, instanceOf()) + } + + @Test + fun `edit profile page can be injected`() { + assertThat(allPages.editProfilePage, instanceOf()) + } + + @Test + fun `follow sone page can be injected`() { + assertThat(allPages.followSonePage, instanceOf()) + } + + @Test + fun `get image page can be injected`() { + assertThat(allPages.getImagePage, instanceOf()) + } + + @Test + fun `image browser page can be injected`() { + assertThat(allPages.imageBrowserPage, instanceOf()) + } + + @Test + fun `index page can be injected`() { + assertThat(allPages.indexPage, instanceOf()) + } + + @Test + fun `known sones page can be injected`() { + assertThat(allPages.knownSonesPage, instanceOf()) + } + + @Test + fun `like page can be injected`() { + assertThat(allPages.likePage, instanceOf()) + } + + @Test + fun `lock sone page can be injected`() { + assertThat(allPages.lockSonePage, instanceOf()) + } + + @Test + fun `login page can be injected`() { + assertThat(allPages.loginPage, instanceOf()) + } + + @Test + fun `logout page can be injected`() { + assertThat(allPages.logoutPage, instanceOf()) + } + + @Test + fun `mark as known page can be injected`() { + assertThat(allPages.markAsKnownPage, instanceOf()) + } + + @Test + fun `new page can be injected`() { + assertThat(allPages.newPage, instanceOf()) + } + + @Test + fun `options page can be injected`() { + assertThat(allPages.optionsPage, instanceOf()) + } + + @Test + fun `rescue page can be injected`() { + assertThat(allPages.rescuePage, instanceOf()) + } + + @Test + fun `search page can be injected`() { + assertThat(allPages.searchPage, instanceOf()) + } + + @Test + fun `trust page can be injected`() { + assertThat(allPages.trustPage, instanceOf()) + } + + @Test + fun `unbookmark page can be injected`() { + assertThat(allPages.unbookmarkPage, instanceOf()) + } + + @Test + fun `unfollow sone page can be injected`() { + assertThat(allPages.unfollowSonePage, instanceOf()) + } + + @Test + fun `unlike page can be injected`() { + assertThat(allPages.unlikePage, instanceOf()) + } + + @Test + fun `unlock sone page can be injected`() { + assertThat(allPages.unlockSonePage, instanceOf()) + } + + @Test + fun `untrust page can be injected`() { + assertThat(allPages.untrustPage, instanceOf()) + } + + @Test + fun `upload image page can be injected`() { + assertThat(allPages.uploadImagePage, instanceOf()) + } + + @Test + fun `view post page can be injected`() { + assertThat(allPages.viewPostPage, instanceOf()) + } + + @Test + fun `view sone page can be injected`() { + assertThat(allPages.viewSonePage, instanceOf()) + } +} + +val baseInjector by lazy { + createInjector( + Core::class.isProvidedByMock(), + FreenetInterface::class.isProvidedByMock(), + Template::class.isProvidedByMock(), + WebInterface::class.isProvidedByDeepMock(), + TemplateRenderer::class.isProvidedByMock() + )!! +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/PageToadletRegistryTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/PageToadletRegistryTest.kt new file mode 100644 index 0000000..d242b32 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/PageToadletRegistryTest.kt @@ -0,0 +1,95 @@ +package net.pterodactylus.sone.web + +import com.google.inject.* +import freenet.clients.http.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.* +import org.junit.* +import org.junit.rules.* +import org.mockito.Mockito.* + +class PageToadletRegistryTest { + + private val pageMaker = mock() + private val toadletContainer = mock() + private val pageToadletFactory = mock() + private val sonePlugin = mock() + + private val injector = Guice.createInjector( + PageMaker::class.isProvidedBy(pageMaker), + ToadletContainer::class.isProvidedBy(toadletContainer), + PageToadletFactory::class.isProvidedBy(pageToadletFactory), + SonePlugin::class.isProvidedBy(sonePlugin) + ) + + @JvmField + @Rule + val expectedException: ExpectedException = ExpectedException.none() + private val pageToadletRegistry = injector.getInstance() + + @Test + fun `registry adds navigation category to page maker`() { + pageToadletRegistry.registerToadlets() + verify(pageMaker).addNavigationCategory("/Sone/index.html", "Navigation.Menu.Sone.Name", "Navigation.Menu.Sone.Tooltip", sonePlugin) + } + + private val page = TestPage() + + @Test + fun `adding a page without menuname will add it correctly`() { + val toadletWithoutMenuname = createPageToadlet() + whenever(pageToadletFactory.createPageToadlet(page)).thenReturn(toadletWithoutMenuname) + pageToadletRegistry.addPage(page) + pageToadletRegistry.registerToadlets() + verify(toadletContainer).register(toadletWithoutMenuname, null, "/Sone/", true, false) + } + + @Test + fun `adding a page with menuname will add it correctly`() { + val toadletWithMenuname = createPageToadlet("Test") + whenever(pageToadletFactory.createPageToadlet(page)).thenReturn(toadletWithMenuname) + pageToadletRegistry.addPage(page) + pageToadletRegistry.registerToadlets() + verify(toadletContainer).register(toadletWithMenuname, "Navigation.Menu.Sone.Name", "/Sone/", true, "Navigation.Menu.Sone.Item.Test.Name", "Navigation.Menu.Sone.Item.Test.Tooltip", false, toadletWithMenuname) + } + + @Test + fun `adding a page after registering will throw an exception`() { + val toadletWithMenuname = createPageToadlet("Test") + whenever(pageToadletFactory.createPageToadlet(page)).thenReturn(toadletWithMenuname) + pageToadletRegistry.registerToadlets() + expectedException.expect(IllegalStateException::class.java) + pageToadletRegistry.addPage(page) + } + + @Test + fun `unregistering toadlets will remove category link`() { + pageToadletRegistry.unregisterToadlets() + verify(pageMaker).removeNavigationCategory("Navigation.Menu.Sone.Name") + } + + @Test + fun `unregistering toadlets will unregister them from the container`() { + val toadletWithMenuname = createPageToadlet("Test") + whenever(pageToadletFactory.createPageToadlet(page)).thenReturn(toadletWithMenuname) + pageToadletRegistry.addPage(page) + pageToadletRegistry.registerToadlets() + pageToadletRegistry.unregisterToadlets() + verify(toadletContainer).unregister(toadletWithMenuname) + } + + private fun createPageToadlet(menuName: String? = null) = + mock().apply { + whenever(this.path()).thenReturn("/Sone/") + whenever(this.menuName).thenReturn(menuName) + } + + private class TestPage : Page { + override fun getPath() = "" + override fun isPrefixPage() = false + override fun handleRequest(freenetRequest: FreenetRequest, response: Response) = response + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/WebInterfaceModuleTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/WebInterfaceModuleTest.kt new file mode 100644 index 0000000..9137da3 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/WebInterfaceModuleTest.kt @@ -0,0 +1,272 @@ +package net.pterodactylus.sone.web + +import com.google.inject.Guice.* +import freenet.client.* +import freenet.clients.http.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.freenet.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.template.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.text.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +class WebInterfaceModuleTest { + + private val webInterfaceModule = WebInterfaceModule() + private val l10n = mock() + private val loaders = mock() + private val additionalModules = arrayOf( + Core::class.isProvidedByMock(), + SoneProvider::class.isProvidedByMock(), + BaseL10n::class.isProvidedBy(l10n), + SoneTextParser::class.isProvidedByMock(), + ElementLoader::class.isProvidedByMock(), + Loaders::class.isProvidedBy(loaders), + HighLevelSimpleClient::class.isProvidedByMock(), + SessionManager::class.isProvidedByMock() + ) + private val injector = createInjector(webInterfaceModule, *additionalModules)!! + private val templateContext by lazy { injector.getInstance().createTemplateContext()!! } + + @Test + fun `template context factory creates template with reflection accessor for objects`() { + verifyAccessor() + } + + @Test + fun `template context factory creates template with collection accessor for collections`() { + verifyAccessor, CollectionAccessor>() + } + + @Test + fun `template context contains sone accessor for sones`() { + verifyAccessor() + } + + @Test + fun `template context contains post accessor for posts`() { + verifyAccessor() + } + + @Test + fun `template context contains reply accessor for replies`() { + verifyAccessor, ReplyAccessor>() + } + + @Test + fun `template context contains album accessor for albums`() { + verifyAccessor() + } + + @Test + fun `template context contains image accessor for images`() { + verifyAccessor() + } + + @Test + fun `template context contains identity accessor for identities`() { + verifyAccessor() + } + + @Test + fun `template context contains trust accessor for trusts`() { + verifyAccessor() + } + + @Test + fun `template context contains http request accessor for http requests`() { + verifyAccessor() + } + + @Test + fun `template context contains profile accessor for profiles`() { + verifyAccessor() + } + + private inline fun verifyAccessor() { + assertThat(templateContext.getAccessor(O::class.java), instanceOf(A::class.java)) + } + + @Test + fun `template context contains date filter`() { + verifyFilter("date") + } + + @Test + fun `template context contains html filter`() { + verifyFilter("html") + } + + @Test + fun `template context contains replace filter`() { + verifyFilter("replace") + } + + @Test + fun `template context contains store filter`() { + verifyFilter("store") + } + + @Test + fun `template context contains l10n filter`() { + verifyFilter("l10n") + } + + @Test + fun `template context contains substring filter`() { + verifyFilter("substring") + } + + @Test + fun `template context contains xml filter`() { + verifyFilter("xml") + } + + @Test + fun `template context contains change filter`() { + verifyFilter("change") + } + + @Test + fun `template context contains match filter`() { + verifyFilter("match") + } + + @Test + fun `template context contains css filter`() { + verifyFilter("css") + } + + @Test + fun `template context contains js filter`() { + verifyFilter("js") + } + + @Test + fun `template context contains parser filter`() { + verifyFilter("parse") + } + + @Test + fun `template context contains shorten filter`() { + verifyFilter("shorten") + } + + @Test + fun `template context contains render filter`() { + verifyFilter("render") + } + + @Test + fun `template context contains linked elements filter`() { + verifyFilter("linked-elements") + } + + @Test + fun `template context contains linked elements render filter`() { + verifyFilter("render-linked-element") + } + + @Test + fun `template context contains reparse filter`() { + verifyFilter("reparse") + } + + @Test + fun `template context contains unknown date filter`() { + verifyFilter("unknown") + } + + @Test + fun `unknown date filter uses correct l10n key`() { + whenever(l10n.getString("View.Sone.Text.UnknownDate")).thenReturn("unknown") + assertThat(getFilter("unknown")!!.format(null, 0L, emptyMap()), equalTo("unknown")) + } + + @Test + fun `template context contains format filter`() { + verifyFilter("format") + } + + @Test + fun `template context contains collection sort filter`() { + verifyFilter("sort") + } + + @Test + fun `template context contains image link filter`() { + verifyFilter("image-link") + } + + @Test + fun `template context contains reply group filter`() { + verifyFilter("replyGroup") + } + + @Test + fun `template context contains contains filter`() { + verifyFilter("in") + } + + @Test + fun `template context unique elements filter`() { + verifyFilter("unique") + } + + @Test + fun `template context mod filter`() { + verifyFilter("mod") + } + + @Test + fun `template context pagination filter`() { + verifyFilter("paginate") + } + + private inline fun verifyFilter(name: String) { + assertThat(getFilter(name), instanceOf(F::class.java)) + } + + private fun getFilter(name: String): Filter? = templateContext.getFilter(name) + + @Test + fun `template context factory is created as singleton`() { + val factory1 = injector.getInstance() + val factory2 = injector.getInstance() + assertThat(factory1, sameInstance(factory2)) + } + + @Test + fun `template from classpath is returned`() { + val template = Template() + templateContext["testTemplate"] = template + assertThat(templateContext.getTemplate("testTemplate"), sameInstance(template)) + } + + @Test + fun `template from loaders’ provider is returned`() { + val template = Template() + whenever(loaders.templateProvider).thenReturn(TemplateProvider { _, templateName -> + template.takeIf { templateName == "testTemplate" } + }) + assertThat(templateContext.getTemplate("testTemplate"), sameInstance(template)) + } + + @Test + fun `page toadlet factory is created with correct prefix`() { + val page = mock>() + assertThat(injector.getInstance().createPageToadlet(page).path(), startsWith("/Sone/")) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.kt index 17c334e..801ea28 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.kt @@ -1,9 +1,11 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Post -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -39,4 +41,9 @@ class BookmarkAjaxPageTest : JsonPageTest("bookmark.ajax", requiresLogin = false verify(core).bookmarkPost(post) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPageTest.kt index 8449453..821198f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPageTest.kt @@ -3,11 +3,14 @@ package net.pterodactylus.sone.web.ajax import com.google.common.base.Optional import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.utils.asOptional +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.hamcrest.Matchers.nullValue import org.junit.Test @@ -89,4 +92,9 @@ class CreatePostAjaxPageTest : JsonPageTest("createPost.ajax", pageSupplier = :: whenever(this.recipientId).thenReturn(recipientId.asOptional()) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt index 829167e..dfbc1db 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt @@ -3,10 +3,13 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -61,4 +64,9 @@ class CreateReplyAjaxPageTest : JsonPageTest("createReply.ajax", pageSupplier = assertThat(json["sone"]?.asText(), equalTo("local-sone")) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPageTest.kt index cee50b9..5ad9531 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPageTest.kt @@ -1,13 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeletePostAjaxPage]. @@ -40,4 +39,9 @@ class DeletePostAjaxPageTest : JsonPageTest("deletePost.ajax", pageSupplier = :: verify(core).deletePost(post) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPageTest.kt index 330bedf..9e4a8e0 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPageTest.kt @@ -1,10 +1,11 @@ package net.pterodactylus.sone.web.ajax -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteProfileFieldAjaxPage]. @@ -27,4 +28,9 @@ class DeleteProfileFieldAjaxPageTest : JsonPageTest("deleteProfileField.ajax", p verify(core).touchConfiguration() } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPageTest.kt index e39332c..0f765dc 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPageTest.kt @@ -1,13 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteReplyAjaxPage]. @@ -41,4 +40,9 @@ class DeleteReplyAjaxPageTest : JsonPageTest("deleteReply.ajax", pageSupplier = verify(core).deleteReply(reply) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPageTest.kt index ff603d2..a43a742 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPageTest.kt @@ -1,12 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.notify.Notification -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.notify.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DismissNotificationAjaxPage]. @@ -35,4 +35,9 @@ class DismissNotificationAjaxPageTest : JsonPageTest("dismissNotification.ajax", verify(notification).dismiss() } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPageTest.kt index 78930e5..868819e 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPageTest.kt @@ -1,9 +1,12 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.verify @@ -34,7 +37,7 @@ class DistrustAjaxPageTest : JsonPageTest("distrustSone.ajax", pageSupplier = :: @Test fun `request with valid sone results in correct trust value being sent back`() { - core.preferences.negativeTrust = -33 + core.preferences.newNegativeTrust = -33 val sone = mock() addSone(sone, "sone-id") addRequestParameter("sone", "sone-id") @@ -42,4 +45,9 @@ class DistrustAjaxPageTest : JsonPageTest("distrustSone.ajax", pageSupplier = :: assertThat(json["trustValue"]?.asInt(), equalTo(-33)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPageTest.kt index 098185b..1528d60 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPageTest.kt @@ -5,10 +5,13 @@ import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.data.impl.AlbumImpl import net.pterodactylus.sone.test.deepMock +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -87,4 +90,9 @@ class EditAlbumAjaxPageTest : JsonPageTest("editAlbum.ajax", pageSupplier = ::Ed assertThat(json["description"]?.asText(), equalTo("foo KSK@foo.html link")) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPageTest.kt index dad6c02..26436a3 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditImageAjaxPageTest.kt @@ -8,10 +8,14 @@ import net.pterodactylus.sone.template.ParserFilter import net.pterodactylus.sone.template.RenderFilter import net.pterodactylus.sone.template.ShortenFilter import net.pterodactylus.sone.test.argumentCaptor +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isProvidedByMock import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq @@ -113,4 +117,13 @@ class EditImageAjaxPageTest : JsonPageTest("editImage.ajax") { assertThat(parameterCaptor.value["sone"], equalTo(sone)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.createChildInjector( + ParserFilter::class.isProvidedByMock(), + ShortenFilter::class.isProvidedByMock(), + RenderFilter::class.isProvidedByMock() + ).getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPageTest.kt index 7eed9ac..6e00c29 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPageTest.kt @@ -1,7 +1,10 @@ package net.pterodactylus.sone.web.ajax +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.verify @@ -43,4 +46,9 @@ class EditProfileFieldAjaxPageTest : JsonPageTest("editProfileField.ajax", pageS verify(currentSone).profile = profile } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPageTest.kt index c649e75..cd4a932 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPageTest.kt @@ -1,12 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [FollowSoneAjaxPage]. @@ -35,4 +35,9 @@ class FollowSoneAjaxPageTest : JsonPageTest("followSone.ajax", pageSupplier = :: verify(core).markSoneKnown(sone) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPageTest.kt index 3a75ded..5f89713 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPageTest.kt @@ -4,11 +4,14 @@ import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Profile import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.contains import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -86,6 +89,11 @@ class GetLikesAjaxPageTest : JsonPageTest("getLikes.ajax", needsFormPassword = f assertThatJsonFailed("invalid-type") } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } private fun createSone(index: Int) = mock().apply { diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt index f49f9f3..fb8b527 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt @@ -1,15 +1,19 @@ package net.pterodactylus.sone.web.ajax import com.fasterxml.jackson.databind.JsonNode +import net.pterodactylus.sone.core.ElementLoader import net.pterodactylus.sone.core.LinkedElement import net.pterodactylus.sone.template.LinkedElementRenderFilter +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isProvidedByMock import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.utils.jsonArray +import net.pterodactylus.sone.web.baseInjector import net.pterodactylus.util.template.TemplateContext import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers -import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.ArgumentMatchers @@ -40,6 +44,14 @@ class GetLinkedElementAjaxPageTest: JsonPageTest("getLinkedElement.ajax", requir )) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.createChildInjector( + ElementLoader::class.isProvidedByMock(), + LinkedElementRenderFilter::class.isProvidedByMock() + ).getInstance(), notNullValue()) + } + private fun JsonNode.toMap() = fields().asSequence().map { it.key!! to if (it.value.isNull) null else it.value.asText()!! }.toMap() } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt index 8084b65..8f67ecf 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt @@ -3,8 +3,10 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.main.SonePlugin import net.pterodactylus.sone.test.argumentCaptor import net.pterodactylus.sone.test.get +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import net.pterodactylus.util.notify.Notification import net.pterodactylus.util.notify.TemplateNotification import net.pterodactylus.util.template.TemplateContext @@ -14,6 +16,7 @@ import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.empty import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.verify @@ -115,4 +118,9 @@ class GetNotificationsAjaxPageTest : JsonPageTest("getNotifications.ajax", requi assertThat(templateContext.value["notification"], equalTo(templateNotification)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPageTest.kt index 8d33542..130bdc2 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPageTest.kt @@ -2,13 +2,16 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.utils.asOptional import net.pterodactylus.sone.utils.asTemplate +import net.pterodactylus.sone.web.baseInjector import net.pterodactylus.util.template.ReflectionAccessor import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -51,4 +54,9 @@ class GetPostAjaxPageTest : JsonPageTest("getPost.ajax", needsFormPassword = fal ).joinToString("\n"))) } + @Test + fun `page can be created dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPageTest.kt index 6af8776..6010e9f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPageTest.kt @@ -2,12 +2,15 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.utils.asTemplate +import net.pterodactylus.sone.web.baseInjector import net.pterodactylus.util.template.ReflectionAccessor import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -49,4 +52,9 @@ class GetReplyAjaxPageTest : JsonPageTest("getReply.ajax", needsFormPassword = f ).joinToString("\n"))) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt index 9576c7c..f270d71 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt @@ -1,17 +1,21 @@ package net.pterodactylus.sone.web.ajax import com.fasterxml.jackson.databind.JsonNode +import net.pterodactylus.sone.core.ElementLoader import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.data.Sone.SoneStatus.downloading import net.pterodactylus.sone.data.Sone.SoneStatus.inserting import net.pterodactylus.sone.freenet.L10nFilter import net.pterodactylus.sone.freenet.L10nText import net.pterodactylus.sone.test.deepMock +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isProvidedByMock import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.text.TimeText import net.pterodactylus.sone.text.TimeTextConverter import net.pterodactylus.sone.utils.jsonArray +import net.pterodactylus.sone.web.baseInjector import net.pterodactylus.util.notify.Notification import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.allOf @@ -19,6 +23,7 @@ import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.emptyIterable import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.hasEntry +import org.hamcrest.Matchers.notNullValue import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any @@ -134,6 +139,15 @@ class GetStatusAjaxPageTest: JsonPageTest("getStatus.ajax", requiresLogin = fals )) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.createChildInjector( + ElementLoader::class.isProvidedByMock(), + TimeTextConverter::class.isProvidedByMock(), + L10nFilter::class.isProvidedByMock() + ).getInstance(), notNullValue()) + } + private fun JsonNode.toMap() = fields().asSequence().map { it.key!! to if (it.value.isNull) null else it.value.asText()!! }.toMap() } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt index fff438b..62a34d1 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt @@ -6,19 +6,23 @@ import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.freenet.L10nFilter import net.pterodactylus.sone.freenet.L10nText import net.pterodactylus.sone.test.get +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.test.isProvidedByMock import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.text.TimeText import net.pterodactylus.sone.text.TimeTextConverter import net.pterodactylus.sone.utils.jsonObject +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.emptyIterable -import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyLong +import java.util.TimeZone import java.util.TimeZone.getTimeZone /** @@ -107,4 +111,13 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f )) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.createChildInjector( + TimeTextConverter::class.isProvidedByMock(), + L10nFilter::class.isProvidedByMock(), + TimeZone::class.isProvidedByMock() + ).getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPageTest.kt index 0d58ca2..ebf4edd 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTranslationAjaxPageTest.kt @@ -1,7 +1,10 @@ package net.pterodactylus.sone.web.ajax +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test /** @@ -17,4 +20,9 @@ class GetTranslationAjaxPageTest : JsonPageTest("getTranslation.ajax", requiresL assertThat(json["value"]?.asText(), equalTo("bar")) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageBaseTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageBaseTest.kt index 75a0cd4..f9554f3 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageBaseTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageBaseTest.kt @@ -23,7 +23,7 @@ class JsonPageBaseTest : TestObjects() { private val outputStream = ByteArrayOutputStream() private val response = Response(outputStream) - private val page = object : JsonPage("path.html", webInterface) { + private val page = object : JsonPage(webInterface) { override val needsFormPassword get() = this@JsonPageBaseTest.needsFormPassword @@ -49,7 +49,7 @@ class JsonPageBaseTest : TestObjects() { @Test fun `page returns 403 is full access is required but request is not full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true page.handleRequest(freenetRequest, response) assertThat(response.statusCode, equalTo(403)) assertThat(response.statusText, equalTo("Forbidden")) diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPageTest.kt index 457aac4..c7da213 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPageTest.kt @@ -2,10 +2,13 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -60,4 +63,9 @@ class LikeAjaxPageTest : JsonPageTest("like.ajax", pageSupplier = ::LikeAjaxPage verify(core, never()).touchConfiguration() } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPageTest.kt index 3a2a524..e3fe5c6 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LockSoneAjaxPageTest.kt @@ -1,11 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LockSoneAjaxPage]. @@ -26,4 +27,9 @@ class LockSoneAjaxPageTest : JsonPageTest("lockSone.ajax", requiresLogin = false verify(core).lockSone(sone) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPageTest.kt index 9578d45..edc8c25 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/LoggedInJsonPageTest.kt @@ -1,6 +1,12 @@ package net.pterodactylus.sone.web.ajax +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* + /** * Unit test for [LoggedInJsonPageTest]. */ -class LoggedInJsonPageTest : JsonPageTest("path", requiresLogin = true, pageSupplier = { webInterface -> LoggedInJsonPage("path", webInterface) }) +class LoggedInJsonPageTest : JsonPageTest("path", requiresLogin = true, pageSupplier = ::TestPage) + +@ToadletPath("path") +class TestPage(webInterface: WebInterface) : LoggedInJsonPage(webInterface) diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPageTest.kt index a3ab0ff..9c37a3d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPageTest.kt @@ -1,16 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.any -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [MarkAsKnownAjaxPage]. @@ -69,4 +65,9 @@ class MarkAsKnownAjaxPageTest : JsonPageTest("markAsKnown.ajax", requiresLogin = verify(core).markReplyKnown(reply2) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPageTest.kt index aab1bbe..847b82c 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPageTest.kt @@ -1,7 +1,10 @@ package net.pterodactylus.sone.web.ajax +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.verify @@ -62,4 +65,9 @@ class MoveProfileFieldAjaxPageTest : JsonPageTest("moveProfileField.ajax", true, verify(currentSone).profile = profile } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPageTest.kt index 64a66a3..d557790 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPageTest.kt @@ -1,9 +1,12 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.verify @@ -31,9 +34,14 @@ class TrustAjaxPageTest : JsonPageTest("trustSone.ajax", requiresLogin = true, n fun `request with valid sone returns positive trust value`() { addSone(sone, "sone-id") addRequestParameter("sone", "sone-id") - core.preferences.positiveTrust = 31 + core.preferences.newPositiveTrust = 31 assertThatJsonIsSuccessful() assertThat(json["trustValue"]?.asInt(), equalTo(31)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPageTest.kt index 65c5beb..b54981f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPageTest.kt @@ -1,9 +1,12 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq @@ -42,4 +45,9 @@ class UnbookmarkAjaxPageTest : JsonPageTest("unbookmark.ajax", requiresLogin = f verify(core).unbookmarkPost(eq(post)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt index b53cc8e..788a398 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt @@ -1,12 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [UnfollowSoneAjaxPage]. @@ -32,4 +32,9 @@ class UnfollowSoneAjaxPageTest : JsonPageTest("unfollowSone.ajax", pageSupplier verify(core).unfollowSone(currentSone, "sone-id") } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPageTest.kt index 4661892..488aacd 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlikeAjaxPageTest.kt @@ -1,7 +1,10 @@ package net.pterodactylus.sone.web.ajax +import net.pterodactylus.sone.test.getInstance +import net.pterodactylus.sone.web.baseInjector import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue import org.junit.Test import org.mockito.Mockito.verify @@ -52,4 +55,9 @@ class UnlikeAjaxPageTest : JsonPageTest("unlike.ajax", pageSupplier = ::UnlikeAj verify(core).touchConfiguration() } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPageTest.kt index 81a54e3..bce6db1 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPageTest.kt @@ -1,11 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [UnlockSoneAjaxPage]. @@ -32,4 +33,9 @@ class UnlockSoneAjaxPageTest : JsonPageTest("unlockSone.ajax", requiresLogin = f verify(core).unlockSone(sone) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPageTest.kt index f2de48d..b693194 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UntrustAjaxPageTest.kt @@ -1,12 +1,12 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [UntrustAjaxPage]. @@ -42,4 +42,9 @@ class UntrustAjaxPageTest : JsonPageTest("untrustSone.ajax", pageSupplier = ::Un assertThat(json["trustValue"], nullValue()) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetRequestTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetRequestTest.kt new file mode 100644 index 0000000..e05ad45 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetRequestTest.kt @@ -0,0 +1,77 @@ +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import freenet.clients.http.SessionManager.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.util.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.* +import org.mockito.Mockito.* +import java.net.* + +class FreenetRequestTest { + + private val uri = URI(".") + private val method = Method.GET + private val httpRequest = mock(HTTPRequest::class.java) + private val toadletContext = mock(ToadletContext::class.java) + private val l10n = mock() + private val sessionManager = mock() + private val request = FreenetRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager) + + @Test + fun `uri is retained correctly`() { + assertThat(request.uri, equalTo(uri)) + } + + @Test + fun `method is retained correctly`() { + assertThat(request.method, equalTo(method)) + } + + @Test + fun `http request is retained correctly`() { + assertThat(request.httpRequest, equalTo(httpRequest)) + } + + @Test + fun `toadlet context is retained correctly`() { + assertThat(request.toadletContext, equalTo(toadletContext)) + } + + @Test + fun `l10n is retained correctly`() { + assertThat(request.l10n, equalTo(l10n)) + } + + @Test + fun `null is returned if no session exists`() { + assertThat(request.existingSession, nullValue()) + } + + @Test + fun `existing session can be retrieved`() { + val session = mock() + whenever(sessionManager.useSession(toadletContext)).thenReturn(session) + assertThat(request.existingSession, sameInstance(session)) + } + + @Test + fun `existing session is returned if it exists`() { + val session = mock() + whenever(sessionManager.useSession(toadletContext)).thenReturn(session) + assertThat(request.session, sameInstance(session)) + } + + @Test + fun `new session is returned if none exists`() { + val session = mock() + whenever(sessionManager.createSession(anyString(), ArgumentMatchers.eq(toadletContext))).thenReturn(session) + assertThat(request.session, sameInstance(session)) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePageTest.kt new file mode 100644 index 0000000..2474d08 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/FreenetTemplatePageTest.kt @@ -0,0 +1,149 @@ +package net.pterodactylus.sone.web.page + +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.util.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* +import java.io.* +import java.nio.charset.StandardCharsets.* + +class FreenetTemplatePageTest { + + private val templateRenderer = deepMock() + private val loaders = mock() + private val page = TestPage(templateRenderer, loaders) + + @Test + fun `path is exposed correctly`() { + assertThat(page.path, equalTo("/test/path")) + } + + @Test + fun `getPageTitle() default implementation returns empty string`() { + assertThat(page.getPageTitle(mock()), equalTo("")) + } + + @Test + fun `isPrefixPage() default implementation returns false`() { + assertThat(page.isPrefixPage, equalTo(false)) + } + + @Test + fun `getStylesheets() default implementation returns empty collection`() { + assertThat(page.styleSheets, empty()) + } + + @Test + fun `getShortcutIcon() default implementation returns null`() { + assertThat(page.shortcutIcon, nullValue()) + } + + @Test + fun `getRedirectTarget() default implementation returns null`() { + assertThat(page.getRedirectTarget(mock()), nullValue()) + } + + @Test + fun `getAdditionalLinkNodes() default implementation returns empty collection`() { + assertThat(page.getAdditionalLinkNodes(mock()), empty()) + } + + @Test + fun `isFullAccessOnly() default implementation returns false`() { + assertThat(page.isFullAccessOnly, equalTo(false)) + } + + @Test + fun `isLinkExcepted() default implementation returns false`() { + assertThat(page.isLinkExcepted(mock()), equalTo(false)) + } + + @Test + fun `isEnabled() returns true if full access only is false`() { + assertThat(page.isEnabled(mock()), equalTo(true)) + } + + @Test + fun `isEnabled() returns false if full access only is true`() { + val page = object : TestPage(templateRenderer, loaders) { + override val isFullAccessOnly = true + } + assertThat(page.isEnabled(mock()), equalTo(false)) + } + + @Test + fun `page with redirect target throws redirect exception on handleRequest`() { + val page = object : TestPage(templateRenderer, loaders) { + override fun getRedirectTarget(request: FreenetRequest) = "foo" + } + val request = mock() + val response = mock() + val pageResponse = page.handleRequest(request, response) + assertThat(pageResponse.statusCode, anyOf(equalTo(302), equalTo(307))) + assertThat(pageResponse.headers, contains(hasHeader("location", "foo"))) + } + + @Test + fun `page with full access only returns unauthorized on handleRequest with non-full access request`() { + val page = object : TestPage(templateRenderer, loaders) { + override val isFullAccessOnly = true + } + val request = deepMock() + val response = Response(null) + val pageResponse = page.handleRequest(request, response) + assertThat(pageResponse.statusCode, equalTo(401)) + } + + @Test + fun `page redirects on POST without form password`() { + val request = deepMock().apply { + whenever(httpRequest.getPartAsStringFailsafe(any(), anyInt())).thenReturn("") + whenever(method).thenReturn(POST) + } + val response = Response(null) + val pageResponse = page.handleRequest(request, response) + assertThat(pageResponse.statusCode, anyOf(equalTo(302), equalTo(307))) + assertThat(pageResponse.headers, contains(hasHeader("location", "invalid-form-password"))) + } + + @Test + fun `page redirects on POST with invalid password`() { + val request = deepMock().apply { + whenever(httpRequest.getPartAsStringFailsafe(any(), anyInt())).thenReturn("invalid") + whenever(method).thenReturn(POST) + } + val response = Response(null) + val pageResponse = page.handleRequest(request, response) + assertThat(pageResponse.statusCode, anyOf(equalTo(302), equalTo(307))) + assertThat(pageResponse.headers, contains(hasHeader("location", "invalid-form-password"))) + } + + @Test + @Dirty + fun `freenet template page creates page with correct title`() { + val page = object : TestPage(templateRenderer, loaders) { + override fun getPageTitle(request: FreenetRequest) = "page title" + } + val request = deepMock() + val pageMakerInteractionFactory = deepMock() + whenever(pageMakerInteractionFactory.createPageMaker(request.toadletContext, "page title").renderPage()).thenReturn("") + setField(page, "pageMakerInteractionFactory", pageMakerInteractionFactory) + val response = page.handleRequest(request, Response(ByteArrayOutputStream())) + assertThat(response.statusCode, equalTo(200)) + assertThat((response.content as ByteArrayOutputStream).toString(UTF_8.name()), equalTo("")) + } + + @Test + fun `template from annotation is loaded`() { + verify(loaders).loadTemplate("template-path") + } + + @TemplatePath("template-path") + @ToadletPath("/test/path") + private open class TestPage(templateRenderer: TemplateRenderer, loaders: Loaders) : FreenetTemplatePage(templateRenderer, loaders, "invalid-form-password") + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactoryTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactoryTest.kt new file mode 100644 index 0000000..8e16094 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionFactoryTest.kt @@ -0,0 +1,28 @@ +package net.pterodactylus.sone.web.page + +import com.google.inject.* +import freenet.clients.http.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* + +class PageMakerInteractionFactoryTest { + + private val pageMakerInteractionFactory: PageMakerInteractionFactory = DefaultPageMakerInteractionFactory() + + @Test + fun `page maker interaction factory can be created by guice`() { + val injector = Guice.createInjector() + assertThat(injector.getInstance(), notNullValue()) + } + + @Test + fun `page maker interaction sets page title correctly`() { + val toadletContext = deepMock() + pageMakerInteractionFactory.createPageMaker(toadletContext, "page title") + verify(toadletContext.pageMaker).getPageNode("page title", toadletContext) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionTest.kt new file mode 100644 index 0000000..178ef09 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/PageMakerInteractionTest.kt @@ -0,0 +1,67 @@ +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import freenet.support.* +import freenet.support.HTMLNode.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.test.TestUtil.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +@Dirty +class PageMakerInteractionTest { + + private val toadletContext = deepMock() + private val pageMaker: PageMaker = toadletContext.pageMaker + private val outerNode = HTMLDoctype("html", "-//W3C//DTD XHTML 1.1//EN") + private val htmlNode: HTMLNode = outerNode.addChild("html") + private val headNode: HTMLNode = htmlNode.addChild("head") + private val contentNode: HTMLNode = htmlNode.addChild("body").addChild("div") + private val pageNode: PageNode = createObject(PageNode::class.java, arrayOf(HTMLNode::class.java, HTMLNode::class.java, HTMLNode::class.java), outerNode, headNode, contentNode) + + init { + whenever(pageMaker.getPageNode("page title", toadletContext)).thenReturn(pageNode) + } + + private val pageMakerInteractions = PageMakerInteraction(toadletContext, "page title") + + @Test + fun `interactions can add style sheet`() { + pageMakerInteractions.addStyleSheet("style.sheet") + assertThat(headNode.children.filter { it.name == "link" }.map { it.attributes }, contains( + mapOf("rel" to "stylesheet", "href" to "style.sheet", "type" to "text/css", "media" to "screen") + )) + } + + @Test + fun `link nodes can be added`() { + pageMakerInteractions.addLinkNode(mapOf("foo" to "bar")) + assertThat(headNode.children.filter { it.name == "link" }.map { it.attributes }, contains( + mapOf("foo" to "bar") + )) + } + + @Test + fun `shortcut icon can be added`() { + pageMakerInteractions.addShortcutIcon("shortcut.icon") + assertThat(headNode.children.filter { it.name == "link" }.map { it.attributes }, contains( + mapOf("rel" to "icon", "href" to "shortcut.icon") + )) + } + + @Test + fun `content can be set`() { + pageMakerInteractions.setContent("foo() +private val sessionManager = mock() +private const val pathPrefix = "/some/prefix/" + +class PageToadletFactoryTest { + + private val pageToadletFactory = PageToadletFactory(highLevelSimpleClient, sessionManager, pathPrefix) + + @Test + fun `page toadlet without menu name is created without menu name`() { + val page = mock>() + val pageToadlet = pageToadletFactory.createPageToadlet(page) + assertThat(pageToadlet.menuName, nullValue()) + } + + @Test + fun `page toadlet with menu name is created with menu name`() { + val page = mock>() + val pageToadlet = pageToadletFactory.createPageToadlet(page, "testName") + assertThat(pageToadlet.menuName, equalTo("testName")) + } + + @Test + fun `path prefix is handed down correctly`() { + val page = mock>().apply { + whenever(path).thenReturn("path") + } + val pageToadlet = pageToadletFactory.createPageToadlet(page) + assertThat(pageToadlet.path(), equalTo("/some/prefix/path")) + } + + @Test + fun `menu name is added from annotation when no menu name is given`() { + val page = TestPageWithMenuName() + val pageToadlet = pageToadletFactory.createPageToadlet(page) + assertThat(pageToadlet.menuName, equalTo("testName")) + } + + @Test + fun `menu name from annotation is ignored when menu name is given`() { + val page = TestPageWithMenuName() + val pageToadlet = pageToadletFactory.createPageToadlet(page, "foo") + assertThat(pageToadlet.menuName, equalTo("foo")) + } + + @Test + fun `page toadlet factory can be created by guice`() { + val injector = Guice.createInjector( + HighLevelSimpleClient::class.isProvidedBy(highLevelSimpleClient), + SessionManager::class.isProvidedBy(sessionManager), + String::class.withNameIsProvidedBy("/Sone/", "toadletPathPrefix") + ) + assertThat(injector.getInstance(), notNullValue()) + } + +} + +@MenuName("testName") +private class TestPageWithMenuName : Page { + + override fun getPath() = "" + override fun isPrefixPage() = false + override fun handleRequest(request: FreenetRequest, response: Response) = response + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/SoneRequestTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/SoneRequestTest.kt new file mode 100644 index 0000000..50c6ce7 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/SoneRequestTest.kt @@ -0,0 +1,62 @@ +package net.pterodactylus.sone.web.page + +import freenet.clients.http.* +import freenet.l10n.* +import freenet.support.api.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.* +import java.net.* + +class SoneRequestTest { + + private val uri = URI(".") + private val method = Method.GET + private val httpRequest = Mockito.mock(HTTPRequest::class.java) + private val toadletContext = Mockito.mock(ToadletContext::class.java) + private val l10n = mock() + private val sessionManager = mock() + private val core = mock() + private val webInterface = mock() + private val soneRequest = SoneRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager, core, webInterface) + + @Test + fun `freenet request properties are retained correctly`() { + assertThat(soneRequest.uri, equalTo(uri)) + assertThat(soneRequest.method, equalTo(method)) + assertThat(soneRequest.httpRequest, equalTo(httpRequest)) + assertThat(soneRequest.toadletContext, equalTo(toadletContext)) + assertThat(soneRequest.l10n, equalTo(l10n)) + assertThat(soneRequest.sessionManager, equalTo(sessionManager)) + } + + @Test + fun `core is retained correctly`() { + assertThat(soneRequest.core, sameInstance(core)) + } + + @Test + fun `web interface is retained correctly`() { + assertThat(soneRequest.webInterface, sameInstance(webInterface)) + } + + @Test + fun `freenet request is wrapped correctly`() { + val freenetRequest = FreenetRequest(uri, method, httpRequest, toadletContext, l10n, sessionManager) + val wrappedSoneRequest = freenetRequest.toSoneRequest(core, webInterface) + assertThat(wrappedSoneRequest.uri, equalTo(uri)) + assertThat(wrappedSoneRequest.method, equalTo(method)) + assertThat(wrappedSoneRequest.httpRequest, equalTo(httpRequest)) + assertThat(wrappedSoneRequest.toadletContext, equalTo(toadletContext)) + assertThat(wrappedSoneRequest.l10n, equalTo(l10n)) + assertThat(wrappedSoneRequest.sessionManager, equalTo(sessionManager)) + assertThat(wrappedSoneRequest.core, sameInstance(core)) + assertThat(wrappedSoneRequest.webInterface, sameInstance(webInterface)) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/page/TemplateRendererTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/page/TemplateRendererTest.kt new file mode 100644 index 0000000..cb03c61 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/page/TemplateRendererTest.kt @@ -0,0 +1,60 @@ +package net.pterodactylus.sone.web.page + +import com.google.inject.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.junit.rules.* + +class TemplateRendererTest { + + @Rule + @JvmField + val expectedException: ExpectedException = ExpectedException.none() + private val templateContextFactory = TemplateContextFactory() + private val templateRenderer = TemplateRenderer(templateContextFactory) + + @Test + fun `renderer can render template`() { + val template = "foo".asTemplate() + val rendered = templateRenderer.render(template) + assertThat(rendered, equalTo("foo")) + } + + @Test + fun `renderer merges template contexts from template and context factory`() { + templateContextFactory.addTemplateObject("a", 1) + val template = "<%a><%b>".asTemplate() + template.initialContext.set("b", 2) + val rendered = templateRenderer.render(template) + assertThat(rendered, equalTo("12")) + } + + @Test + fun `template context can be processed`() { + templateContextFactory.addTemplateObject("a", 1) + val template = "<%a><%b><%c>".asTemplate() + template.initialContext.set("b", 2) + val rendered = templateRenderer.render(template) { templateContext -> templateContext.set("c", 3) } + assertThat(rendered, equalTo("123")) + } + + @Test + fun `redirect exceptions are thrown`() { + expectedException.expect(RedirectException::class.java) + templateRenderer.render(Template()) { _ -> throw RedirectException("foo") } + } + + @Test + fun `template renderer can be created by guice`() { + val injector = Guice.createInjector( + TemplateContextFactory::class.isProvidedByMock() + ) + assertThat(injector.getInstance(), notNullValue()) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/AboutPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/AboutPageTest.kt index 142bf81..c3f0f76 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/AboutPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/AboutPageTest.kt @@ -1,16 +1,17 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.main.SonePlugin.PluginHomepage -import net.pterodactylus.sone.main.SonePlugin.PluginVersion -import net.pterodactylus.sone.main.SonePlugin.PluginYear -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [AboutPage]. */ -class AboutPageTest: WebPageTest({ template, webInterface -> AboutPage(template, webInterface, PluginVersion(version), PluginYear(year), PluginHomepage(homepage)) }) { +class AboutPageTest : WebPageTest({ webInterface, loaders, templateRenderer -> AboutPage(webInterface, loaders, templateRenderer, PluginVersion(version), PluginYear(year), PluginHomepage(homepage)) }) { companion object { private const val version = "0.1.2" @@ -46,4 +47,24 @@ class AboutPageTest: WebPageTest({ template, webInterface -> AboutPage(template, assertThat(templateContext["year"], equalTo(year)) } + @Test + fun `about page can be created by dependency injection`() { + val injector = baseInjector.createChildInjector( + PluginVersion::class.isProvidedByMock(), + PluginYear::class.isProvidedByMock(), + PluginHomepage::class.isProvidedByMock() + ) + assertThat(injector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("About")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/about.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarkPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarkPageTest.kt index a805843..292c4a7 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarkPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarkPageTest.kt @@ -1,11 +1,12 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -13,7 +14,7 @@ import org.mockito.Mockito.verify /** * Unit test for [BookmarkPage]. */ -class BookmarkPageTest: WebPageTest(::BookmarkPage) { +class BookmarkPageTest : WebPageTest(::BookmarkPage) { @Test fun `path is set correctly`() { @@ -51,4 +52,9 @@ class BookmarkPageTest: WebPageTest(::BookmarkPage) { } } + @Test + fun `bookmark page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarksPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarksPageTest.kt index e853199..3668755 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarksPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/BookmarksPageTest.kt @@ -1,19 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.Pagination -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [BookmarksPage]. */ -class BookmarksPageTest: WebPageTest(::BookmarksPage) { +class BookmarksPageTest : WebPageTest(::BookmarksPage) { private val post1 = createLoadedPost(1000) private val post2 = createLoadedPost(3000) @@ -27,7 +26,7 @@ class BookmarksPageTest: WebPageTest(::BookmarksPage) { @Before fun setupBookmarkedPostsAndPagination() { whenever(core.bookmarkedPosts).thenReturn(setOf(post1, post2, post3)) - core.preferences.postsPerPage = 5 + core.preferences.newPostsPerPage = 5 } @Test @@ -56,4 +55,19 @@ class BookmarksPageTest: WebPageTest(::BookmarksPage) { } } + @Test + fun `bookmarks page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Bookmarks")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/bookmarks.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPageTest.kt index 5cc463a..224791f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPageTest.kt @@ -1,22 +1,21 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Album.Modifier -import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty -import net.pterodactylus.sone.test.deepMock -import net.pterodactylus.sone.test.selfMock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Album.* +import net.pterodactylus.sone.data.Album.Modifier.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [CreateAlbumPage]. */ -class CreateAlbumPageTest: WebPageTest(::CreateAlbumPage) { +class CreateAlbumPageTest : WebPageTest(::CreateAlbumPage) { private val parentAlbum = createAlbum("parent-id") private val newAlbum = createAlbum("album-id") @@ -96,4 +95,14 @@ class CreateAlbumPageTest: WebPageTest(::CreateAlbumPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/createAlbum.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreatePostPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreatePostPageTest.kt index 3b1cc8c..2bf0c05 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreatePostPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreatePostPageTest.kt @@ -1,19 +1,21 @@ package net.pterodactylus.sone.web.pages -import com.google.common.base.Optional.absent -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.utils.asOptional -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import com.google.common.base.Optional.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [CreatePostPage]. */ -class CreatePostPageTest: WebPageTest(::CreatePostPage) { +class CreatePostPageTest : WebPageTest(::CreatePostPage) { @Test fun `page returns correct path`() { @@ -88,4 +90,14 @@ class CreatePostPageTest: WebPageTest(::CreatePostPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/createPost.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPageTest.kt index 71e83bc..062a010 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPageTest.kt @@ -1,18 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [CreateReplyPage]. */ -class CreateReplyPageTest: WebPageTest(::CreateReplyPage) { +class CreateReplyPageTest : WebPageTest(::CreateReplyPage) { @Test fun `page returns correct path`() { @@ -85,4 +86,14 @@ class CreateReplyPageTest: WebPageTest(::CreateReplyPage) { verifyRedirect("noPermission.html") } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/createReply.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateSonePageTest.kt index 9cbf2c3..6a4a2b0 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/CreateSonePageTest.kt @@ -1,22 +1,21 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.wot.OwnIdentity -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.verify /** * Unit test for [CreateSonePage]. */ -class CreateSonePageTest: WebPageTest(::CreateSonePage) { +class CreateSonePageTest : WebPageTest(::CreateSonePage) { private val localSones_ = listOf( createSone("local-sone1"), @@ -111,7 +110,7 @@ class CreateSonePageTest: WebPageTest(::CreateSonePage) { @Test fun `create sone is not shown in menu if full access is required but client doesn’t have full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true assertThat(page.isEnabled(toadletContext), equalTo(false)) } @@ -136,10 +135,25 @@ class CreateSonePageTest: WebPageTest(::CreateSonePage) { @Test fun `create sone is shown in menu if no sone is logged in and client has full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true whenever(toadletContext.isAllowedFullAccess).thenReturn(true) unsetCurrentSone() assertThat(page.isEnabled(toadletContext), equalTo(true)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with the correct menuname`() { + assertThat(page.menuName, equalTo("CreateSone")) + } + + @Test + fun `page is annotated with the correct template path`() { + assertThat(page.templatePath, equalTo("/templates/createSone.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPageTest.kt index 969a133..55b3d70 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPageTest.kt @@ -1,21 +1,20 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.verify /** * Unit test for [DeleteAlbumPage]. */ -class DeleteAlbumPageTest: WebPageTest(::DeleteAlbumPage) { +class DeleteAlbumPageTest : WebPageTest(::DeleteAlbumPage) { private val sone = mock() private val album = mock() @@ -96,7 +95,7 @@ class DeleteAlbumPageTest: WebPageTest(::DeleteAlbumPage) { fun `album is deleted and page redirects to album if parent album is not root album`() { setMethod(POST) whenever(parentAlbum.isRoot).thenReturn(false) - whenever(sone.rootAlbum).thenReturn(mock()) + whenever(sone.rootAlbum).thenReturn(mock()) addAlbum("album-id", album) addHttpRequestPart("album", "album-id") verifyRedirect("imageBrowser.html?album=parent-id") { @@ -104,4 +103,14 @@ class DeleteAlbumPageTest: WebPageTest(::DeleteAlbumPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deleteAlbum.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePageTest.kt index 1b90c4a..cecde50 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePageTest.kt @@ -1,21 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteImagePage]. */ -class DeleteImagePageTest: WebPageTest(::DeleteImagePage) { +class DeleteImagePageTest : WebPageTest(::DeleteImagePage) { private val image = mock() private val sone = mock() @@ -80,4 +78,14 @@ class DeleteImagePageTest: WebPageTest(::DeleteImagePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deleteImage.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeletePostPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeletePostPageTest.kt index 5ccd5c2..9464920 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeletePostPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeletePostPageTest.kt @@ -1,21 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeletePostPage]. */ -class DeletePostPageTest: WebPageTest(::DeletePostPage) { +class DeletePostPageTest : WebPageTest(::DeletePostPage) { private val post = mock() private val sone = mock() @@ -28,12 +26,12 @@ class DeletePostPageTest: WebPageTest(::DeletePostPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("deletePost.html")) + assertThat(page.path, equalTo("deletePost.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test @@ -102,4 +100,14 @@ class DeletePostPageTest: WebPageTest(::DeletePostPage) { assertThat(templateContext["returnPage"], equalTo("return.html")) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deletePost.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPageTest.kt index 8f344eb..728966c 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPageTest.kt @@ -1,21 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.any -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteProfileFieldPage]. */ -class DeleteProfileFieldPageTest: WebPageTest(::DeleteProfileFieldPage) { +class DeleteProfileFieldPageTest : WebPageTest(::DeleteProfileFieldPage) { private val profile = Profile(currentSone) private val field = profile.addField("name") @@ -75,4 +73,14 @@ class DeleteProfileFieldPageTest: WebPageTest(::DeleteProfileFieldPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deleteProfileField.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPageTest.kt index c332557..f9a07c2 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPageTest.kt @@ -1,21 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteReplyPage]. */ -class DeleteReplyPageTest: WebPageTest(::DeleteReplyPage) { +class DeleteReplyPageTest : WebPageTest(::DeleteReplyPage) { private val sone = mock() private val reply = mock() @@ -28,12 +26,12 @@ class DeleteReplyPageTest: WebPageTest(::DeleteReplyPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("deleteReply.html")) + assertThat(page.path, equalTo("deleteReply.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test @@ -95,4 +93,14 @@ class DeleteReplyPageTest: WebPageTest(::DeleteReplyPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deleteReply.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePageTest.kt index 415adf6..21cfdfc 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePageTest.kt @@ -1,33 +1,33 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.any -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DeleteSonePage]. */ -class DeleteSonePageTest: WebPageTest(::DeleteSonePage) { +class DeleteSonePageTest : WebPageTest(::DeleteSonePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("deleteSone.html")) + assertThat(page.path, equalTo("deleteSone.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - whenever(l10n.getString("Page.DeleteSone.Title")).thenReturn("delete sone page") - assertThat(page.getPageTitle(freenetRequest), equalTo("delete sone page")) + whenever(l10n.getString("Page.DeleteSone.Title")).thenReturn("delete sone page") + assertThat(page.getPageTitle(soneRequest), equalTo("delete sone page")) } @Test @@ -52,4 +52,19 @@ class DeleteSonePageTest: WebPageTest(::DeleteSonePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("DeleteSone")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/deleteSone.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPageTest.kt index 41f47aa..e8583df 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DismissNotificationPageTest.kt @@ -1,19 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.notify.Notification -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.notify.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DismissNotificationPage]. */ -class DismissNotificationPageTest: WebPageTest(::DismissNotificationPage) { +class DismissNotificationPageTest : WebPageTest(::DismissNotificationPage) { private val notification = mock() @@ -30,7 +29,7 @@ class DismissNotificationPageTest: WebPageTest(::DismissNotificationPage) { @Test fun `page returns correct title`() { whenever(l10n.getString("Page.DismissNotification.Title")).thenReturn("dismiss notification page") - assertThat(page.getPageTitle(freenetRequest), equalTo("dismiss notification page")) + assertThat(page.getPageTitle(soneRequest), equalTo("dismiss notification page")) } @Test @@ -63,4 +62,9 @@ class DismissNotificationPageTest: WebPageTest(::DismissNotificationPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/DistrustPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/DistrustPageTest.kt index 3261df6..d706e05 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/DistrustPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/DistrustPageTest.kt @@ -1,18 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [DistrustPage]. */ -class DistrustPageTest: WebPageTest(::DistrustPage) { +class DistrustPageTest : WebPageTest(::DistrustPage) { @Test fun `page returns correct path`() { @@ -27,7 +27,7 @@ class DistrustPageTest: WebPageTest(::DistrustPage) { @Test fun `page returns correct title`() { whenever(l10n.getString("Page.Distrust.Title")).thenReturn("distrust page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("distrust page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("distrust page title")) } @Test @@ -54,4 +54,9 @@ class DistrustPageTest: WebPageTest(::DistrustPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPageTest.kt index b4328c6..4d435b4 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPageTest.kt @@ -1,23 +1,20 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Album.Modifier -import net.pterodactylus.sone.data.Album.Modifier.AlbumTitleMustNotBeEmpty -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.mockBuilder -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Album.* +import net.pterodactylus.sone.data.Album.Modifier.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [EditAlbumPage]. */ -class EditAlbumPageTest: WebPageTest(::EditAlbumPage) { +class EditAlbumPageTest : WebPageTest(::EditAlbumPage) { private val album = mock() private val parentAlbum = mock() @@ -49,7 +46,7 @@ class EditAlbumPageTest: WebPageTest(::EditAlbumPage) { @Test fun `page returns correct title`() { whenever(l10n.getString("Page.EditAlbum.Title")).thenReturn("edit album page") - assertThat(page.getPageTitle(freenetRequest), equalTo("edit album page")) + assertThat(page.getPageTitle(soneRequest), equalTo("edit album page")) } @Test @@ -120,4 +117,9 @@ class EditAlbumPageTest: WebPageTest(::EditAlbumPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditImagePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditImagePageTest.kt index f6eb02e..0961622 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditImagePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditImagePageTest.kt @@ -1,26 +1,20 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Image.Modifier -import net.pterodactylus.sone.data.Image.Modifier.ImageTitleMustNotBeEmpty -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.doThrow -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.mockBuilder -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Image.* +import net.pterodactylus.sone.data.Image.Modifier.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [EditImagePage]. */ -class EditImagePageTest: WebPageTest(::EditImagePage) { +class EditImagePageTest : WebPageTest(::EditImagePage) { private val image = mock() private val modifier = mockBuilder() @@ -44,13 +38,13 @@ class EditImagePageTest: WebPageTest(::EditImagePage) { @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { whenever(l10n.getString("Page.EditImage.Title")).thenReturn("edit image page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("edit image page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("edit image page title")) } @Test @@ -145,4 +139,9 @@ class EditImagePageTest: WebPageTest(::EditImagePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPageTest.kt index b4acc7e..7731fa2 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPageTest.kt @@ -1,19 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [EditProfileFieldPage]. */ -class EditProfileFieldPageTest: WebPageTest(::EditProfileFieldPage) { +class EditProfileFieldPageTest : WebPageTest(::EditProfileFieldPage) { private val profile = Profile(currentSone) private val field = profile.addField("Name") @@ -25,18 +25,18 @@ class EditProfileFieldPageTest: WebPageTest(::EditProfileFieldPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("editProfileField.html")) + assertThat(page.path, equalTo("editProfileField.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { whenever(l10n.getString("Page.EditProfileField.Title")).thenReturn("edit profile field title") - assertThat(page.getPageTitle(freenetRequest), equalTo("edit profile field title")) + assertThat(page.getPageTitle(soneRequest), equalTo("edit profile field title")) } @Test @@ -93,4 +93,14 @@ class EditProfileFieldPageTest: WebPageTest(::EditProfileFieldPage) { assertThat(templateContext["duplicateFieldName"], equalTo(true)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/editProfileField.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt index b4e6570..a31f04c 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt @@ -1,23 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.notNullValue -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [EditProfilePage]. */ -class EditProfilePageTest: WebPageTest(::EditProfilePage) { +class EditProfilePageTest : WebPageTest(::EditProfilePage) { private val profile = Profile(currentSone) private val firstField = profile.addField("First Field") @@ -40,18 +36,18 @@ class EditProfilePageTest: WebPageTest(::EditProfilePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("editProfile.html")) + assertThat(page.path, equalTo("editProfile.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - whenever(l10n.getString("Page.EditProfile.Title")).thenReturn("edit profile page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("edit profile page title")) + whenever(l10n.getString("Page.EditProfile.Title")).thenReturn("edit profile page title") + assertThat(page.getPageTitle(soneRequest), equalTo("edit profile page title")) } @Test @@ -218,4 +214,19 @@ class EditProfilePageTest: WebPageTest(::EditProfilePage) { verifyRedirect("editProfileField.html?field=${firstField.id}") } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("EditProfile")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/editProfile.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/ErrorPagesTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/ErrorPagesTest.kt new file mode 100644 index 0000000..6f8bfa1 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/ErrorPagesTest.kt @@ -0,0 +1,103 @@ +package net.pterodactylus.sone.web.pages + +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +class ErrorPagesTest { + + private val webPageTest = WebPageTest() + + private fun testPage(page: (WebInterface, Loaders, TemplateRenderer) -> FreenetTemplatePage, test: (FreenetTemplatePage) -> Unit) = + with(webPageTest) { + test(page(webInterface, loaders, templateRenderer)) + } + + @Test + fun `invalid page returns correct path`() { + testPage(::InvalidPage) { page -> + assertThat(page.path, equalTo("invalid.html")) + } + } + + @Test + fun `invalid page returns correct title`() { + testPage(::InvalidPage) { page -> + assertThat(page.getPageTitle(webPageTest.freenetRequest), equalTo("Page.Invalid.Title")) + } + } + + @Test + fun `invalid page is annotated with correct template path`() { + testPage(::InvalidPage) { page -> + assertThat(page.templatePath, equalTo("/templates/invalid.html")) + } + } + + @Test + fun `no permission page returns correct path`() { + testPage(::NoPermissionPage) { page -> + assertThat(page.path, equalTo("noPermission.html")) + } + } + + @Test + fun `no permission page returns correct title`() { + testPage(::NoPermissionPage) { page -> + assertThat(page.getPageTitle(webPageTest.freenetRequest), equalTo("Page.NoPermission.Title")) + } + } + + @Test + fun `no permission page is annotated with correct template path`() { + testPage(::NoPermissionPage) { page -> + assertThat(page.templatePath, equalTo("/templates/noPermission.html")) + } + } + + @Test + fun `empty image title page returns correct path`() { + testPage(::EmptyImageTitlePage) { page -> + assertThat(page.path, equalTo("emptyImageTitle.html")) + } + } + + @Test + fun `empty image title page returns correct page title`() { + testPage(::EmptyImageTitlePage) { page -> + assertThat(page.getPageTitle(webPageTest.freenetRequest), equalTo("Page.EmptyImageTitle.Title")) + } + } + + @Test + fun `empty image title page is annotated with correct template path`() { + testPage(::EmptyImageTitlePage) { page -> + assertThat(page.templatePath, equalTo("/templates/emptyImageTitle.html")) + } + } + + @Test + fun `empty album title page returns correct path`() { + testPage(::EmptyAlbumTitlePage) { page -> + assertThat(page.path, equalTo("emptyAlbumTitle.html")) + } + } + + @Test + fun `empty album title page returns correct page title`() { + testPage(::EmptyAlbumTitlePage) { page -> + assertThat(page.getPageTitle(webPageTest.freenetRequest), equalTo("Page.EmptyAlbumTitle.Title")) + } + } + + @Test + fun `empty album title page is annotated with correct template path`() { + testPage(::EmptyAlbumTitlePage) { page -> + assertThat(page.templatePath, equalTo("/templates/emptyAlbumTitle.html")) + } + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/FollowSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/FollowSonePageTest.kt index 21964aa..ba1dc42 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/FollowSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/FollowSonePageTest.kt @@ -1,13 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.ArgumentMatchers +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.* import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyString import org.mockito.Mockito.never @@ -16,22 +16,22 @@ import org.mockito.Mockito.verify /** * Unit test for [FollowSonePage]. */ -class FollowSonePageTest: WebPageTest(::FollowSonePage) { +class FollowSonePageTest : WebPageTest(::FollowSonePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("followSone.html")) + assertThat(page.path, equalTo("followSone.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - whenever(l10n.getString("Page.FollowSone.Title")).thenReturn("follow sone page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("follow sone page title")) + whenever(l10n.getString("Page.FollowSone.Title")).thenReturn("follow sone page title") + assertThat(page.getPageTitle(soneRequest), equalTo("follow sone page title")) } @Test @@ -80,4 +80,9 @@ class FollowSonePageTest: WebPageTest(::FollowSonePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/GetImagePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/GetImagePageTest.kt index b5efeac..f4428bd 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/GetImagePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/GetImagePageTest.kt @@ -1,10 +1,12 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.TemporaryImage -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.net.* /** * Unit test for [GetImagePage]. @@ -29,7 +31,7 @@ class GetImagePageTest { @Test fun `page is not link-excepted`() { - assertThat(page.isLinkExcepted(null), equalTo(false)) + assertThat(page.isLinkExcepted(URI("")), equalTo(false)) } @Test @@ -59,4 +61,9 @@ class GetImagePageTest { )) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPageTest.kt index 4d0b2c7..a0e9372 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPageTest.kt @@ -1,34 +1,33 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.net.* /** * Unit test for [ImageBrowserPage]. */ -class ImageBrowserPageTest: WebPageTest(::ImageBrowserPage) { +class ImageBrowserPageTest : WebPageTest(::ImageBrowserPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("imageBrowser.html")) + assertThat(page.path, equalTo("imageBrowser.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { whenever(l10n.getString("Page.ImageBrowser.Title")).thenReturn("image browser page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("image browser page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("image browser page title")) } @Test @@ -87,7 +86,7 @@ class ImageBrowserPageTest: WebPageTest(::ImageBrowserPage) { @Test fun `get request for gallery can show second page`() { - core.preferences.imagesPerPage = 2 + core.preferences.newImagesPerPage = 2 val firstSone = createSone("first album", "second album") addSone("sone1", firstSone) val secondSone = createSone("third album", "fourth album") @@ -130,7 +129,22 @@ class ImageBrowserPageTest: WebPageTest(::ImageBrowserPage) { @Test fun `page is link-excepted`() { - assertThat(page.isLinkExcepted(null), equalTo(true)) + assertThat(page.isLinkExcepted(URI("")), equalTo(true)) + } + + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("ImageBrowser")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/imageBrowser.html")) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt index b51627d..9104127 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt @@ -1,25 +1,22 @@ package net.pterodactylus.sone.web.pages -import com.google.common.base.Optional.fromNullable -import com.google.common.base.Predicate -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.notify.PostVisibilityFilter -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.Pagination -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.emptyIterable -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import org.mockito.ArgumentMatchers +import com.google.common.base.* +import com.google.common.base.Optional.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.notify.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.* /** * Unit test for [IndexPage]. */ -class IndexPageTest: WebPageTest({ template, webInterface -> IndexPage(template, webInterface, postVisibilityFilter) }) { +class IndexPageTest : WebPageTest({ webInterface, loaders, templateRenderer -> IndexPage(webInterface, loaders, templateRenderer, postVisibilityFilter) }) { companion object { private val postVisibilityFilter = mock() @@ -27,18 +24,18 @@ class IndexPageTest: WebPageTest({ template, webInterface -> IndexPage(template, @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("index.html")) + assertThat(page.path, equalTo("index.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { whenever(l10n.getString("Page.Index.Title")).thenReturn("index page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("index page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("index page title")) } @Before @@ -134,7 +131,7 @@ class IndexPageTest: WebPageTest({ template, webInterface -> IndexPage(template, fun `index page sets page correctly`() { val posts = listOf(createPost(3000), createPost(2000), createPost(1000)) whenever(currentSone.posts).thenReturn(posts) - core.preferences.postsPerPage = 1 + core.preferences.newPostsPerPage = 1 addHttpRequestParameter("page", "2") page.processTemplate(freenetRequest, templateContext) @Suppress("UNCHECKED_CAST") @@ -143,7 +140,7 @@ class IndexPageTest: WebPageTest({ template, webInterface -> IndexPage(template, @Test fun `index page without posts sets correct pagination`() { - core.preferences.postsPerPage = 1 + core.preferences.newPostsPerPage = 1 page.processTemplate(freenetRequest, templateContext) @Suppress("UNCHECKED_CAST") (templateContext["pagination"] as Pagination).let { pagination -> @@ -151,4 +148,19 @@ class IndexPageTest: WebPageTest({ template, webInterface -> IndexPage(template, } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Index")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/index.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPageTest.kt index 70a5eea..37e0e95 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/KnownSonesPageTest.kt @@ -1,26 +1,19 @@ package net.pterodactylus.sone.web.pages -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.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.wot.Identity -import net.pterodactylus.sone.freenet.wot.OwnIdentity -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.Pagination -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [KnownSonesPage]. */ -class KnownSonesPageTest: WebPageTest(::KnownSonesPage) { +class KnownSonesPageTest : WebPageTest(::KnownSonesPage) { private val sones = listOf( createSone(1000, 4, 7, 2, "sone2", true, true), @@ -50,7 +43,7 @@ class KnownSonesPageTest: WebPageTest(::KnownSonesPage) { whenever(albums).thenReturn(listOf(album)) } whenever(this.rootAlbum).thenReturn(rootAlbum) - whenever(this.profile).thenReturn(mock()) + whenever(this.profile).thenReturn(mock()) whenever(id).thenReturn(name.toLowerCase()) whenever(this.name).thenReturn(name) } @@ -81,7 +74,7 @@ class KnownSonesPageTest: WebPageTest(::KnownSonesPage) { @Test fun `page returns correct title`() { whenever(l10n.getString("Page.KnownSones.Title")).thenReturn("known sones page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("known sones page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("known sones page title")) } @Test @@ -242,4 +235,19 @@ class KnownSonesPageTest: WebPageTest(::KnownSonesPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with the correct menuname`() { + assertThat(page.menuName, equalTo("KnownSones")) + } + + @Test + fun `page is annotated with corrrect template path`() { + assertThat(page.templatePath, equalTo("/templates/knownSones.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/LikePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/LikePageTest.kt index 9a08737..4140644 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/LikePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/LikePageTest.kt @@ -1,31 +1,32 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyNoMoreInteractions +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LikePage]. */ -class LikePageTest: WebPageTest(::LikePage) { +class LikePageTest : WebPageTest(::LikePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("like.html")) + assertThat(page.path, equalTo("like.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - addTranslation("Page.Like.Title", "like page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("like page title")) + addTranslation("Page.Like.Title", "like page title") + assertThat(page.getPageTitle(soneRequest), equalTo("like page title")) } @Test @@ -65,4 +66,9 @@ class LikePageTest: WebPageTest(::LikePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/LockSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/LockSonePageTest.kt index 2a9b4ed..de42141 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/LockSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/LockSonePageTest.kt @@ -1,11 +1,12 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -13,7 +14,7 @@ import org.mockito.Mockito.verify /** * Unit test for [LockSonePage]. */ -class LockSonePageTest: WebPageTest(::LockSonePage) { +class LockSonePageTest : WebPageTest(::LockSonePage) { @Test fun `page returns correct path`() { @@ -22,13 +23,13 @@ class LockSonePageTest: WebPageTest(::LockSonePage) { @Test fun `page does not require login`() { - assertThat(page.requiresLogin(), equalTo(false)) + assertThat(page.requiresLogin(), equalTo(false)) } @Test fun `page returns correct title`() { - addTranslation("Page.LockSone.Title", "lock Sone page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("lock Sone page title")) + addTranslation("Page.LockSone.Title", "lock Sone page title") + assertThat(page.getPageTitle(soneRequest), equalTo("lock Sone page title")) } @Test @@ -52,4 +53,9 @@ class LockSonePageTest: WebPageTest(::LockSonePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/LoginPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/LoginPageTest.kt index 1b409b7..067857e 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/LoginPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/LoginPageTest.kt @@ -1,25 +1,20 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.freenet.wot.Identity -import net.pterodactylus.sone.freenet.wot.OwnIdentity -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.thenReturnMock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.containsInAnyOrder -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Before -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LoginPage]. */ -class LoginPageTest: WebPageTest(::LoginPage) { +class LoginPageTest : WebPageTest(::LoginPage) { private val sones = listOf(createSone("Sone", "Test"), createSone("Test"), createSone("Sone")) @@ -45,12 +40,12 @@ class LoginPageTest: WebPageTest(::LoginPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("login.html")) + assertThat(page.path, equalTo("login.html")) } @Test fun `page does not require login`() { - assertThat(page.requiresLogin(), equalTo(false)) + assertThat(page.requiresLogin(), equalTo(false)) } @Test @@ -108,7 +103,7 @@ class LoginPageTest: WebPageTest(::LoginPage) { @Test fun `page is not enabled if full access required and request is not full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true assertThat(page.isEnabled(toadletContext), equalTo(false)) } @@ -125,7 +120,7 @@ class LoginPageTest: WebPageTest(::LoginPage) { @Test fun `page is enabled if full access required and request is full access and there is no current sone`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true unsetCurrentSone() whenever(toadletContext.isAllowedFullAccess).thenReturn(true) assertThat(page.isEnabled(toadletContext), equalTo(true)) @@ -133,9 +128,24 @@ class LoginPageTest: WebPageTest(::LoginPage) { @Test fun `page is not enabled if full access required and request is full access but there is a current sone`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true whenever(toadletContext.isAllowedFullAccess).thenReturn(true) assertThat(page.isEnabled(toadletContext), equalTo(false)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Login")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/login.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/LogoutPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/LogoutPageTest.kt index 9dbc82a..fae95d2 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/LogoutPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/LogoutPageTest.kt @@ -1,15 +1,17 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [LogoutPage]. */ -class LogoutPageTest: WebPageTest(::LogoutPage) { +class LogoutPageTest : WebPageTest(::LogoutPage) { @Test fun `page returns correct path`() { @@ -24,7 +26,7 @@ class LogoutPageTest: WebPageTest(::LogoutPage) { @Test fun `page returns correct title`() { addTranslation("Page.Logout.Title", "logout page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("logout page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("logout page title")) } @Test @@ -36,7 +38,7 @@ class LogoutPageTest: WebPageTest(::LogoutPage) { @Test fun `page is not enabled if sone requires full access and request does not have full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true assertThat(page.isEnabled(toadletContext), equalTo(false)) } @@ -60,10 +62,20 @@ class LogoutPageTest: WebPageTest(::LogoutPage) { @Test fun `page is enabled if full access is required and present and sone is logged in and there is more than one sone`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true whenever(toadletContext.isAllowedFullAccess).thenReturn(true) whenever(core.localSones).thenReturn(listOf(currentSone, currentSone)) assertThat(page.isEnabled(toadletContext), equalTo(true)) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Logout")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPageTest.kt index d9a132a..6142e3a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPageTest.kt @@ -1,19 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [MarkAsKnownPage]. */ -class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { +class MarkAsKnownPageTest : WebPageTest(::MarkAsKnownPage) { @Test fun `page returns correct path`() { @@ -28,7 +27,7 @@ class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { @Test fun `page returns correct title`() { addTranslation("Page.MarkAsKnown.Title", "mark as known page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("mark as known page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("mark as known page title")) } @Test @@ -37,7 +36,7 @@ class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { addHttpRequestPart("returnPage", "return.html") addHttpRequestPart("type", "post") addHttpRequestPart("id", "post1 post2 post3") - val posts = listOf(mock(), mock()) + val posts = listOf(mock(), mock()) addPost("post1", posts[0]) addPost("post3", posts[1]) verifyRedirect("return.html") { @@ -52,7 +51,7 @@ class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { addHttpRequestPart("returnPage", "return.html") addHttpRequestPart("type", "reply") addHttpRequestPart("id", "reply1 reply2 reply3") - val replies = listOf(mock(), mock()) + val replies = listOf(mock(), mock()) addPostReply("reply1", replies[0]) addPostReply("reply3", replies[1]) verifyRedirect("return.html") { @@ -67,7 +66,7 @@ class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { addHttpRequestPart("returnPage", "return.html") addHttpRequestPart("type", "sone") addHttpRequestPart("id", "sone1 sone2 sone3") - val sones = listOf(mock(), mock()) + val sones = listOf(mock(), mock()) addSone("sone1", sones[0]) addSone("sone3", sones[1]) verifyRedirect("return.html") { @@ -83,4 +82,9 @@ class MarkAsKnownPageTest: WebPageTest(::MarkAsKnownPage) { verifyRedirect("invalid.html") } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/NewPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/NewPageTest.kt index 96427e7..a4d7617 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/NewPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/NewPageTest.kt @@ -1,27 +1,23 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.asOptional -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.containsInAnyOrder -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test -import java.util.Arrays.asList +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.util.Arrays.* /** * Unit test for [NewPage]. */ -class NewPageTest: WebPageTest(::NewPage) { +class NewPageTest : WebPageTest(::NewPage) { @Before fun setupNumberOfPostsPerPage() { - webInterface.core.preferences.postsPerPage = 5 + webInterface.core.preferences.newPostsPerPage = 5 } @Test @@ -37,14 +33,14 @@ class NewPageTest: WebPageTest(::NewPage) { @Test fun `page returns correct title`() { addTranslation("Page.New.Title", "new page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("new page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("new page title")) } @Test fun `posts are not duplicated when they come from both new posts and new replies notifications`() { val extraPost = mock().withTime(2000) val posts = asList(mock().withTime(1000), mock().withTime(3000)) - val postReplies = asList(mock(), mock()) + val postReplies = asList(mock(), mock()) whenever(postReplies[0].post).thenReturn(posts[0].asOptional()) whenever(postReplies[1].post).thenReturn(extraPost.asOptional()) whenever(webInterface.getNewPosts(currentSone)).thenReturn(posts) @@ -61,7 +57,7 @@ class NewPageTest: WebPageTest(::NewPage) { @Test @Suppress("UNCHECKED_CAST") fun `posts are paginated properly`() { - webInterface.core.preferences.postsPerPage = 2 + webInterface.core.preferences.newPostsPerPage = 2 val posts = listOf(mock().withTime(2000), mock().withTime(3000), mock().withTime(1000)) whenever(webInterface.getNewPosts(currentSone)).thenReturn(posts) verifyNoRedirect { @@ -72,7 +68,7 @@ class NewPageTest: WebPageTest(::NewPage) { @Test @Suppress("UNCHECKED_CAST") fun `posts are paginated properly on second page`() { - webInterface.core.preferences.postsPerPage = 2 + webInterface.core.preferences.newPostsPerPage = 2 addHttpRequestParameter("page", "1") val posts = listOf(mock().withTime(2000), mock().withTime(3000), mock().withTime(1000)) whenever(webInterface.getNewPosts(currentSone)).thenReturn(posts) @@ -81,4 +77,19 @@ class NewPageTest: WebPageTest(::NewPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with the correct menuname`() { + assertThat(page.menuName, equalTo("New")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/new.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/OptionsPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/OptionsPageTest.kt index 4e4c02e..71e1b7b 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/OptionsPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/OptionsPageTest.kt @@ -1,38 +1,35 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.SoneOptions.DefaultSoneOptions -import net.pterodactylus.sone.data.SoneOptions.LoadExternalContent.FOLLOWED -import net.pterodactylus.sone.data.SoneOptions.LoadExternalContent.TRUSTED +import net.pterodactylus.sone.data.SoneOptions.* +import net.pterodactylus.sone.data.SoneOptions.LoadExternalContent.* +import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.* import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.hasItem -import org.hamcrest.Matchers.nullValue -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [OptionsPage]. */ -class OptionsPageTest: WebPageTest(::OptionsPage) { +class OptionsPageTest : WebPageTest(::OptionsPage) { @Before fun setupPreferences() { - core.preferences.insertionDelay = 1 - core.preferences.charactersPerPost = 50 - core.preferences.fcpFullAccessRequired = WRITING - core.preferences.imagesPerPage = 4 - core.preferences.isFcpInterfaceActive = true - core.preferences.isRequireFullAccess = true - core.preferences.negativeTrust = 7 - core.preferences.positiveTrust = 8 - core.preferences.postCutOffLength = 51 - core.preferences.postsPerPage = 10 - core.preferences.trustComment = "11" + core.preferences.newInsertionDelay = 1 + core.preferences.newCharactersPerPost = 50 + core.preferences.newFcpFullAccessRequired = WRITING + core.preferences.newImagesPerPage = 4 + core.preferences.newFcpInterfaceActive = true + core.preferences.newRequireFullAccess = true + core.preferences.newNegativeTrust = 7 + core.preferences.newPositiveTrust = 8 + core.preferences.newPostCutOffLength = 51 + core.preferences.newPostsPerPage = 10 + core.preferences.newTrustComment = "11" } @Before @@ -61,7 +58,7 @@ class OptionsPageTest: WebPageTest(::OptionsPage) { @Test fun `page returns correct title`() { addTranslation("Page.Options.Title", "options page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("options page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("options page title")) } @Test @@ -268,22 +265,22 @@ class OptionsPageTest: WebPageTest(::OptionsPage) { @Test fun `fcp interface can be set to true`() { - verifyThatPreferencesCanBeSet("fcp-interface-active", "checked", true) { core.preferences.isFcpInterfaceActive } + verifyThatPreferencesCanBeSet("fcp-interface-active", "checked", true) { core.preferences.fcpInterfaceActive } } @Test fun `fcp interface can be set to false`() { - verifyThatPreferencesCanBeSet("fcp-interface-active", null, false) { core.preferences.isFcpInterfaceActive } + verifyThatPreferencesCanBeSet("fcp-interface-active", null, false) { core.preferences.fcpInterfaceActive } } @Test fun `require full access can be set to true`() { - verifyThatPreferencesCanBeSet("require-full-access", "checked", true) { core.preferences.isRequireFullAccess } + verifyThatPreferencesCanBeSet("require-full-access", "checked", true) { core.preferences.requireFullAccess } } @Test fun `require full access can be set to false`() { - verifyThatPreferencesCanBeSet("require-full-access", null, false) { core.preferences.isRequireFullAccess } + verifyThatPreferencesCanBeSet("require-full-access", null, false) { core.preferences.requireFullAccess } } @Test @@ -376,4 +373,19 @@ class OptionsPageTest: WebPageTest(::OptionsPage) { verifyThatPreferencesCanBeSet("trust-comment", "", "Set from Sone Web Interface") { core.preferences.trustComment } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Options")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/options.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/ReloadingPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/ReloadingPageTest.kt index 7ebb052..99cf8bf 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/ReloadingPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/ReloadingPageTest.kt @@ -1,13 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.web.page.FreenetRequest -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder -import java.nio.file.Files -import java.nio.file.Paths +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.junit.rules.* +import java.nio.file.* import kotlin.text.Charsets.UTF_8 /** @@ -15,7 +15,9 @@ import kotlin.text.Charsets.UTF_8 */ class ReloadingPageTest { - @Rule @JvmField val tempFolder = TemporaryFolder() + @Rule + @JvmField + val tempFolder = TemporaryFolder() private val folder by lazy { tempFolder.newFolder()!! } private val page by lazy { ReloadingPage("/prefix/", folder.path, "text/plain") } private val webPageTest = WebPageTest() @@ -52,4 +54,9 @@ class ReloadingPageTest { assertThat(responseBytes.toByteArray(), equalTo("Hello\nWorld\n".toByteArray())) } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance>(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/RescuePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/RescuePageTest.kt index e8ec10a..d11352f 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/RescuePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/RescuePageTest.kt @@ -1,13 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.core.SoneRescuer -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -15,7 +15,7 @@ import org.mockito.Mockito.verify /** * Unit test for [RescuePage]. */ -class RescuePageTest: WebPageTest(::RescuePage) { +class RescuePageTest : WebPageTest(::RescuePage) { private val soneRescuer = mock() @@ -37,7 +37,7 @@ class RescuePageTest: WebPageTest(::RescuePage) { @Test fun `page returns correct title`() { addTranslation("Page.Rescue.Title", "rescue page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("rescue page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("rescue page title")) } @Test @@ -85,4 +85,19 @@ class RescuePageTest: WebPageTest(::RescuePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct menuname`() { + assertThat(page.menuName, equalTo("Rescue")) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/rescue.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt index 94af5da..329f458 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/SearchPageTest.kt @@ -1,28 +1,22 @@ package net.pterodactylus.sone.web.pages -import com.google.common.base.Optional.absent -import com.google.common.base.Ticker -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.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.isOnPage -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicInteger +import com.google.common.base.* +import com.google.common.base.Optional.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.util.concurrent.* +import java.util.concurrent.atomic.* /** * Unit test for [SearchPage]. */ -class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(template, webInterface, ticker) }) { +class SearchPageTest : WebPageTest({ webInterface, loaders, templateRenderer -> SearchPage(webInterface, loaders, templateRenderer, ticker) }) { companion object { val ticker = mock() @@ -41,7 +35,7 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `page returns correct title`() { addTranslation("Page.Search.Title", "search page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("search page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("search page title")) } @Test @@ -63,28 +57,28 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `searching for sone link redirects to view sone page`() { - addSone("sone-id", mock()) - addHttpRequestParameter("query", "sone://sone-id") - verifyRedirect("viewSone.html?sone=sone-id") + addSone("Sone-ID", mock()) + addHttpRequestParameter("query", "sone://Sone-ID") + verifyRedirect("viewSone.html?sone=Sone-ID") } @Test fun `searching for sone link without prefix redirects to view sone page`() { - addSone("sone-id", mock()) + addSone("sone-id", mock()) addHttpRequestParameter("query", "sone-id") verifyRedirect("viewSone.html?sone=sone-id") } @Test fun `searching for a post link redirects to post page`() { - addPost("post-id", mock()) - addHttpRequestParameter("query", "post://post-id") - verifyRedirect("viewPost.html?post=post-id") + addPost("Post-id", mock()) + addHttpRequestParameter("query", "post://Post-id") + verifyRedirect("viewPost.html?post=Post-id") } @Test fun `searching for a post ID without prefix redirects to post page`() { - addPost("post-id", mock()) + addPost("post-id", mock()) addHttpRequestParameter("query", "post-id") verifyRedirect("viewPost.html?post=post-id") } @@ -92,8 +86,8 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `searching for a reply link redirects to the post page`() { val postReply = mock().apply { whenever(postId).thenReturn("post-id") } - addPostReply("reply-id", postReply) - addHttpRequestParameter("query", "reply://reply-id") + addPostReply("Reply-id", postReply) + addHttpRequestParameter("query", "reply://Reply-id") verifyRedirect("viewPost.html?post=post-id") } @@ -107,28 +101,28 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `searching for an album link redirects to the image browser`() { - addAlbum("album-id", mock()) + addAlbum("album-id", mock()) addHttpRequestParameter("query", "album://album-id") verifyRedirect("imageBrowser.html?album=album-id") } @Test fun `searching for an album ID redirects to the image browser`() { - addAlbum("album-id", mock()) + addAlbum("album-id", mock()) addHttpRequestParameter("query", "album-id") verifyRedirect("imageBrowser.html?album=album-id") } @Test fun `searching for an image link redirects to the image browser`() { - addImage("image-id", mock()) + addImage("image-id", mock()) addHttpRequestParameter("query", "image://image-id") verifyRedirect("imageBrowser.html?image=image-id") } @Test fun `searching for an image ID redirects to the image browser`() { - addImage("image-id", mock()) + addImage("image-id", mock()) addHttpRequestParameter("query", "image-id") verifyRedirect("imageBrowser.html?image=image-id") } @@ -282,7 +276,7 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `sone hits are paginated correctly`() { - core.preferences.postsPerPage = 2 + core.preferences.newPostsPerPage = 2 val sones = listOf(createSone("1Sone"), createSone("Other1"), createSone("22Sone"), createSone("333Sone"), createSone("Other2")) .onEach { addSone(it.id, it) } addHttpRequestParameter("query", "sone") @@ -294,7 +288,7 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `sone hits page 2 is shown correctly`() { - core.preferences.postsPerPage = 2 + core.preferences.newPostsPerPage = 2 val sones = listOf(createSone("1Sone"), createSone("Other1"), createSone("22Sone"), createSone("333Sone"), createSone("Other2")) .onEach { addSone(it.id, it) } addHttpRequestParameter("query", "sone") @@ -307,7 +301,7 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `post hits are paginated correctly`() { - core.preferences.postsPerPage = 2 + core.preferences.newPostsPerPage = 2 val sones = listOf(createSoneWithPost("match1", "1Sone"), createSoneWithPost("no-match1", "Other1"), createSoneWithPost("match2", "22Sone"), createSoneWithPost("match3", "333Sone"), createSoneWithPost("no-match2", "Other2")) addHttpRequestParameter("query", "sone") verifyNoRedirect { @@ -318,7 +312,7 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Test fun `post hits page 2 is shown correctly`() { - core.preferences.postsPerPage = 2 + core.preferences.newPostsPerPage = 2 val sones = listOf(createSoneWithPost("match1", "1Sone"), createSoneWithPost("no-match1", "Other1"), createSoneWithPost("match2", "22Sone"), createSoneWithPost("match3", "333Sone"), createSoneWithPost("no-match2", "Other2")) addHttpRequestParameter("query", "sone") addHttpRequestParameter("postPage", "1") @@ -364,4 +358,14 @@ class SearchPageTest: WebPageTest({ template, webInterface -> SearchPage(templat @Suppress("UNCHECKED_CAST") private operator fun get(key: String): T? = templateContext[key] as? T + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/search.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePageTest.kt index 3cb08e6..8e29df1 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/SoneTemplatePageTest.kt @@ -1,39 +1,38 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.main.SonePlugin -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.notify.Notification -import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.main.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.notify.* +import net.pterodactylus.util.template.* import net.pterodactylus.util.version.Version -import org.hamcrest.Matcher -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.anyOf -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.containsInAnyOrder -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Test +import org.hamcrest.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* /** * Unit test for [SoneTemplatePage]. */ -class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : SoneTemplatePage("path.html", template, webInterface, true) {} }) { +class SoneTemplatePageTest : WebPageTest({ webInterface, loaders, templateRenderer -> object : SoneTemplatePage(webInterface, loaders, templateRenderer, requiresLogin = true) {} }) { + + init { + request("index.html") + } @Test fun `page title is empty string if no page title key was given`() { - SoneTemplatePage("path.html", template, null, webInterface).let { page -> - assertThat(page.getPageTitle(freenetRequest), equalTo("")) + SoneTemplatePage(webInterface, loaders, templateRenderer, requiresLogin = false).let { page -> + assertThat(page.getPageTitle(soneRequest), equalTo("")) } } @Test fun `page title is retrieved from l10n if page title key is given`() { - SoneTemplatePage("path.html", template, "page.title", webInterface).let { page -> + SoneTemplatePage(webInterface, loaders, templateRenderer, pageTitleKey = "page.title", requiresLogin = false).let { page -> whenever(l10n.getString("page.title")).thenReturn("Page Title") - assertThat(page.getPageTitle(freenetRequest), equalTo("Page Title")) + assertThat(page.getPageTitle(soneRequest), equalTo("Page Title")) } } @@ -78,7 +77,7 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `local sones are set in template context`() { - val localSones = listOf(mock(), mock()) + val localSones = listOf(mock(), mock()) whenever(core.localSones).thenReturn(localSones) verifyVariableMatches("localSones", containsInAnyOrder(*localSones.toTypedArray())) } @@ -144,7 +143,7 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `handleRequest method is called`() { var called = false - val page = object : SoneTemplatePage("path.html", template, webInterface, true) { + val page = object : SoneTemplatePage(webInterface, loaders, templateRenderer, requiresLogin = true) { override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { called = true } @@ -155,7 +154,7 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `redirect does not happen if login is not required`() { - val page = SoneTemplatePage("page.html", template, webInterface, false) + val page = SoneTemplatePage(webInterface, loaders, templateRenderer, requiresLogin = false) assertThat(page.getRedirectTarget(freenetRequest), nullValue()) } @@ -167,14 +166,12 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `redirect does happen if sone is not logged in`() { unsetCurrentSone() - request("index.html") assertThat(page.getRedirectTarget(freenetRequest), equalTo("login.html?target=index.html")) } @Test fun `redirect does happen with parameters encoded correctly if sone is not logged in`() { unsetCurrentSone() - request("index.html") addHttpRequestParameter("foo", "b=r") addHttpRequestParameter("baz", "q&o") assertThat(page.getRedirectTarget(freenetRequest), anyOf( @@ -185,7 +182,7 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `page is disabled if full access is required but request does not have full access`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true assertThat(page.isEnabled(toadletContext), equalTo(false)) } @@ -202,16 +199,28 @@ class SoneTemplatePageTest : WebPageTest({ template, webInterface -> object : So @Test fun `page is enabled if full access is required and request has full access and login is required and there is a current sone`() { - core.preferences.isRequireFullAccess = true + core.preferences.newRequireFullAccess = true whenever(toadletContext.isAllowedFullAccess).thenReturn(true) assertThat(page.isEnabled(toadletContext), equalTo(true)) } @Test fun `page is enabled if no full access is required and login is not required`() { - SoneTemplatePage("path.html", template, webInterface, false).let { page -> + SoneTemplatePage(webInterface, loaders, templateRenderer, requiresLogin = false).let { page -> assertThat(page.isEnabled(toadletContext), equalTo(true)) } } + @Test + fun `handle request with sone request is called`() { + var called = false + val page = object : SoneTemplatePage(webInterface, loaders, templateRenderer) { + override fun handleRequest(soneRequest: SoneRequest, templateContext: TemplateContext) { + called = true + } + } + page.processTemplate(freenetRequest, templateContext) + assertThat(called, equalTo(true)) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/TrustPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/TrustPageTest.kt index cc77203..990c1b7 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/TrustPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/TrustPageTest.kt @@ -1,11 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.never @@ -14,22 +16,22 @@ import org.mockito.Mockito.verify /** * Unit test for [TrustPage]. */ -class TrustPageTest: WebPageTest(::TrustPage) { +class TrustPageTest : WebPageTest(::TrustPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("trust.html")) + assertThat(page.path, equalTo("trust.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - addTranslation("Page.Trust.Title", "title trust page") - assertThat(page.getPageTitle(freenetRequest), equalTo("title trust page")) + addTranslation("Page.Trust.Title", "title trust page") + assertThat(page.getPageTitle(soneRequest), equalTo("title trust page")) } @Test @@ -68,4 +70,9 @@ class TrustPageTest: WebPageTest(::TrustPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPageTest.kt index a9f784e..4025fe4 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPageTest.kt @@ -1,23 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.test.capture -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.any -import org.mockito.Mockito.never -import org.mockito.Mockito.times -import org.mockito.Mockito.verify +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [UnbookmarkPage]. */ -class UnbookmarkPageTest: WebPageTest(::UnbookmarkPage) { +class UnbookmarkPageTest : WebPageTest(::UnbookmarkPage) { @Test fun `page returns correct path`() { @@ -32,7 +27,7 @@ class UnbookmarkPageTest: WebPageTest(::UnbookmarkPage) { @Test fun `page returns correct title`() { addTranslation("Page.Unbookmark.Title", "unbookmark page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("unbookmark page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("unbookmark page title")) } @Test @@ -77,4 +72,9 @@ class UnbookmarkPageTest: WebPageTest(::UnbookmarkPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePageTest.kt index 01721cd..39f4fd5 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePageTest.kt @@ -1,30 +1,32 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.verify +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* /** * Unit test for [UnfollowSonePage]. */ -class UnfollowSonePageTest: WebPageTest(::UnfollowSonePage) { +class UnfollowSonePageTest : WebPageTest(::UnfollowSonePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("unfollowSone.html")) + assertThat(page.path, equalTo("unfollowSone.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct page title`() { - addTranslation("Page.UnfollowSone.Title", "unfollow page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("unfollow page title")) + addTranslation("Page.UnfollowSone.Title", "unfollow page title") + assertThat(page.getPageTitle(soneRequest), equalTo("unfollow page title")) } @Test @@ -53,4 +55,9 @@ class UnfollowSonePageTest: WebPageTest(::UnfollowSonePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlikePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlikePageTest.kt index fe00729..2d8ef89 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlikePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlikePageTest.kt @@ -1,9 +1,11 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -11,22 +13,22 @@ import org.mockito.Mockito.verify /** * Unit test for [UnlikePage]. */ -class UnlikePageTest: WebPageTest(::UnlikePage) { +class UnlikePageTest : WebPageTest(::UnlikePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("unlike.html")) + assertThat(page.path, equalTo("unlike.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { addTranslation("Page.Unlike.Title", "unlike page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("unlike page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("unlike page title")) } @Test @@ -68,4 +70,9 @@ class UnlikePageTest: WebPageTest(::UnlikePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePageTest.kt index 6d46922..8627fd4 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UnlockSonePageTest.kt @@ -1,12 +1,12 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.Mockito.never import org.mockito.Mockito.verify @@ -14,22 +14,22 @@ import org.mockito.Mockito.verify /** * Unit test for [UnlockSonePage]. */ -class UnlockSonePageTest: WebPageTest(::UnlockSonePage) { +class UnlockSonePageTest : WebPageTest(::UnlockSonePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("unlockSone.html")) + assertThat(page.path, equalTo("unlockSone.html")) } @Test fun `page does not require login`() { - assertThat(page.requiresLogin(), equalTo(false)) + assertThat(page.requiresLogin(), equalTo(false)) } @Test fun `page returns correct title`() { addTranslation("Page.UnlockSone.Title", "unlock page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("unlock page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("unlock page title")) } @Test @@ -56,7 +56,7 @@ class UnlockSonePageTest: WebPageTest(::UnlockSonePage) { setMethod(POST) addHttpRequestPart("returnPage", "return.html") addHttpRequestPart("sone", "remote-sone") - addSone("remote-sone", mock()) + addSone("remote-sone", mock()) verifyRedirect("return.html") { verify(core, never()).unlockSone(any()) } @@ -74,4 +74,9 @@ class UnlockSonePageTest: WebPageTest(::UnlockSonePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UntrustPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UntrustPageTest.kt index 9d18162..eb0ebdd 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UntrustPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UntrustPageTest.kt @@ -1,11 +1,13 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test +import net.pterodactylus.sone.web.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.never @@ -14,22 +16,22 @@ import org.mockito.Mockito.verify /** * Unit test for [UntrustPage]. */ -class UntrustPageTest: WebPageTest(::UntrustPage) { +class UntrustPageTest : WebPageTest(::UntrustPage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("untrust.html")) + assertThat(page.path, equalTo("untrust.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { addTranslation("Page.Untrust.Title", "untrust page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("untrust page title")) + assertThat(page.getPageTitle(soneRequest), equalTo("untrust page title")) } @Test @@ -70,4 +72,9 @@ class UntrustPageTest: WebPageTest(::UntrustPage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/UploadImagePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/UploadImagePageTest.kt index 58e63a2..370c0a7 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/UploadImagePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/UploadImagePageTest.kt @@ -1,26 +1,24 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Image.Modifier -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.data.TemporaryImage +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Image.* +import net.pterodactylus.sone.test.getInstance import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.mockBuilder import net.pterodactylus.sone.test.whenever -import net.pterodactylus.util.web.Method.POST -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import org.mockito.Mockito.any +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import net.pterodactylus.util.web.Method.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.Mockito.* import org.mockito.Mockito.eq -import org.mockito.Mockito.never -import org.mockito.Mockito.verify /** * Unit test for [UploadImagePage]. */ -class UploadImagePageTest: WebPageTest(::UploadImagePage) { +class UploadImagePageTest : WebPageTest(::UploadImagePage) { private val parentAlbum = mock().apply { whenever(id).thenReturn("parent-id") @@ -29,18 +27,18 @@ class UploadImagePageTest: WebPageTest(::UploadImagePage) { @Test fun `page returns correct path`() { - assertThat(page.path, equalTo("uploadImage.html")) + assertThat(page.path, equalTo("uploadImage.html")) } @Test fun `page requires login`() { - assertThat(page.requiresLogin(), equalTo(true)) + assertThat(page.requiresLogin(), equalTo(true)) } @Test fun `page returns correct title`() { - addTranslation("Page.UploadImage.Title", "upload image page title") - assertThat(page.getPageTitle(freenetRequest), equalTo("upload image page title")) + addTranslation("Page.UploadImage.Title", "upload image page title") + assertThat(page.getPageTitle(soneRequest), equalTo("upload image page title")) } @Test @@ -61,7 +59,7 @@ class UploadImagePageTest: WebPageTest(::UploadImagePage) { fun `post request with parent that is not the current sone results in no permission error page`() { setMethod(POST) addHttpRequestPart("parent", "parent-id") - whenever(parentAlbum.sone).thenReturn(mock()) + whenever(parentAlbum.sone).thenReturn(mock()) addAlbum("parent-id", parentAlbum) verifyRedirect("noPermission.html") } @@ -115,4 +113,14 @@ class UploadImagePageTest: WebPageTest(::UploadImagePage) { } } + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/invalid.html")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewPostPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewPostPageTest.kt index b66f6cc..6ba1550 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewPostPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewPostPageTest.kt @@ -1,18 +1,18 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.net.* /** * Unit test for [ViewPostPage]. */ -class ViewPostPageTest: WebPageTest(::ViewPostPage) { +class ViewPostPageTest : WebPageTest(::ViewPostPage) { private val post = mock() @@ -28,7 +28,7 @@ class ViewPostPageTest: WebPageTest(::ViewPostPage) { @Test fun `the view post page is link-excepted`() { - assertThat(page.isLinkExcepted(null), equalTo(true)) + assertThat(page.isLinkExcepted(URI("")), equalTo(true)) } @Test @@ -72,14 +72,14 @@ class ViewPostPageTest: WebPageTest(::ViewPostPage) { @Test fun `page title for request without parameters is default title`() { addTranslation("Page.ViewPost.Title", "view post title") - assertThat(page.getPageTitle(freenetRequest), equalTo("view post title")) + assertThat(page.getPageTitle(soneRequest), equalTo("view post title")) } @Test fun `page title for request with invalid post is default title`() { addHttpRequestParameter("post", "invalid-post-id") addTranslation("Page.ViewPost.Title", "view post title") - assertThat(page.getPageTitle(freenetRequest), equalTo("view post title")) + assertThat(page.getPageTitle(soneRequest), equalTo("view post title")) } @Test @@ -94,7 +94,17 @@ class ViewPostPageTest: WebPageTest(::ViewPostPage) { addPost("post-id", post) addHttpRequestParameter("post", "post-id") addTranslation("Page.ViewPost.Title", "view post title") - assertThat(page.getPageTitle(freenetRequest), equalTo("This is a text that … - First M. Last - view post title")) + assertThat(page.getPageTitle(soneRequest), equalTo("This is a text that … - First M. Last - view post title")) + } + + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/viewPost.html")) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewSonePageTest.kt index d7ff46d..6e97e36 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewSonePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/ViewSonePageTest.kt @@ -1,25 +1,19 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.isOnPage -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.Pagination -import net.pterodactylus.sone.utils.asOptional -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.contains -import org.hamcrest.Matchers.equalTo -import org.hamcrest.Matchers.nullValue -import org.junit.Before -import org.junit.Test +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import java.net.* /** * Unit test for [ViewSonePage]. */ -class ViewSonePageTest: WebPageTest(::ViewSonePage) { +class ViewSonePageTest : WebPageTest(::ViewSonePage) { init { whenever(currentSone.id).thenReturn("sone-id") @@ -27,17 +21,17 @@ class ViewSonePageTest: WebPageTest(::ViewSonePage) { private val post1 = createPost("post1", "First Post.", 1000, currentSone) private val post2 = createPost("post2", "Second Post.", 2000, currentSone) - private val foreignPost1 = createPost("foreign-post1", "First Foreign Post.", 1000, mock()) - private val foreignPost2 = createPost("foreign-post2", "Second Foreign Post.", 2000, mock()) - private val foreignPost3 = createPost("foreign-post3", "Third Foreign Post.", 3000, mock()) - private val directed1 = createPost("post3", "First directed.", 1500, mock(), recipient = currentSone) - private val directed2 = createPost("post4", "Second directed.", 2500, mock(), recipient = currentSone) + private val foreignPost1 = createPost("foreign-post1", "First Foreign Post.", 1000, mock()) + private val foreignPost2 = createPost("foreign-post2", "Second Foreign Post.", 2000, mock()) + private val foreignPost3 = createPost("foreign-post3", "Third Foreign Post.", 3000, mock()) + private val directed1 = createPost("post3", "First directed.", 1500, mock(), recipient = currentSone) + private val directed2 = createPost("post4", "Second directed.", 2500, mock(), recipient = currentSone) @Before fun setup() { whenever(currentSone.posts).thenReturn(mutableListOf(post2, post1)) whenever(core.getDirectedPosts("sone-id")).thenReturn(setOf(directed1, directed2)) - core.preferences.postsPerPage = 2 + core.preferences.newPostsPerPage = 2 } @Test @@ -176,14 +170,14 @@ class ViewSonePageTest: WebPageTest(::ViewSonePage) { @Test fun `page title is default for request without parameters`() { addTranslation("Page.ViewSone.Page.TitleWithoutSone", "view sone page without sone") - assertThat(page.getPageTitle(freenetRequest), equalTo("view sone page without sone")) + assertThat(page.getPageTitle(soneRequest), equalTo("view sone page without sone")) } @Test fun `page title is default for request with invalid sone parameters`() { addHttpRequestParameter("sone", "invalid-sone-id") addTranslation("Page.ViewSone.Page.TitleWithoutSone", "view sone page without sone") - assertThat(page.getPageTitle(freenetRequest), equalTo("view sone page without sone")) + assertThat(page.getPageTitle(soneRequest), equalTo("view sone page without sone")) } @Test @@ -196,12 +190,22 @@ class ViewSonePageTest: WebPageTest(::ViewSonePage) { lastName = "Last" }) addTranslation("Page.ViewSone.Title", "view sone page") - assertThat(page.getPageTitle(freenetRequest), equalTo("First M. Last - view sone page")) + assertThat(page.getPageTitle(soneRequest), equalTo("First M. Last - view sone page")) } @Test fun `page is link-excepted`() { - assertThat(page.isLinkExcepted(null), equalTo(true)) + assertThat(page.isLinkExcepted(URI("")), equalTo(true)) + } + + @Test + fun `page can be created by dependency injection`() { + assertThat(baseInjector.getInstance(), notNullValue()) + } + + @Test + fun `page is annotated with correct template path`() { + assertThat(page.templatePath, equalTo("/templates/viewSone.html")) } } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt index ce16c85..f51bece 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt @@ -1,60 +1,60 @@ package net.pterodactylus.sone.web.pages -import com.google.common.eventbus.EventBus -import freenet.clients.http.ToadletContext -import freenet.support.SimpleReadOnlyArrayBucket -import freenet.support.api.HTTPRequest -import freenet.support.api.HTTPUploadedFile -import net.pterodactylus.sone.core.Preferences -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.Sone -import net.pterodactylus.sone.data.TemporaryImage -import net.pterodactylus.sone.freenet.wot.OwnIdentity +import com.google.common.eventbus.* +import freenet.clients.http.* +import freenet.support.* +import freenet.support.api.* +import net.pterodactylus.sone.core.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.freenet.wot.* +import net.pterodactylus.sone.main.* import net.pterodactylus.sone.test.deepMock import net.pterodactylus.sone.test.get import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asList -import net.pterodactylus.sone.utils.asOptional -import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.sone.utils.* +import net.pterodactylus.sone.web.* +import net.pterodactylus.sone.web.page.* import net.pterodactylus.sone.web.page.FreenetTemplatePage.RedirectException -import net.pterodactylus.util.notify.Notification -import net.pterodactylus.util.template.Template -import net.pterodactylus.util.template.TemplateContext -import net.pterodactylus.util.web.Method -import net.pterodactylus.util.web.Method.GET -import net.pterodactylus.util.web.Response -import org.junit.Assert.fail -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.ArgumentMatchers.anyLong -import org.mockito.ArgumentMatchers.anyString +import net.pterodactylus.util.notify.* +import net.pterodactylus.util.template.* +import net.pterodactylus.util.web.* +import net.pterodactylus.util.web.Method.* +import org.junit.Assert.* +import org.mockito.ArgumentMatchers.* import org.mockito.ArgumentMatchers.eq -import java.io.ByteArrayOutputStream -import java.net.URI -import java.nio.charset.Charset +import java.io.* +import java.net.* +import java.nio.charset.* import kotlin.text.Charsets.UTF_8 /** * Base class for web page tests. */ -open class WebPageTest(pageSupplier: (Template, WebInterface) -> SoneTemplatePage = { _, _ -> mock() }) { +open class WebPageTest(pageSupplier: (WebInterface, Loaders, TemplateRenderer) -> SoneTemplatePage = { _, _, _ -> mock() }) { val currentSone = mock() - val template = mock