From: David ‘Bombe’ Roden Date: Thu, 30 Nov 2017 05:55:54 +0000 (+0100) Subject: Merge branch 'release-0.9.8' X-Git-Tag: 0.9.8^0 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=6f1f26e3998cfef155b0cf59152827accea70d30;hp=ffd92ca2374c0b2218e583d02e0bdd24b8c110ae Merge branch 'release-0.9.8' --- diff --git a/build.gradle b/build.gradle index ecdbfdd..8111c2a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ group = 'net.pterodactylus' -version = '0.9.7' +version = '0.9.8' buildscript { - ext.kotlinVersion = '1.1.51' + ext.kotlinVersion = '1.2.0' repositories { mavenCentral() } @@ -54,7 +54,7 @@ dependencies { testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-test' testCompile group: 'junit', name: 'junit', version: '4.11' - testCompile group: 'org.mockito', name: 'mockito-core', version: '2.1.0' + testCompile group: 'org.mockito', name: 'mockito-core', version: '2.10.0' testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3' } diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 66677de..7384eda 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -51,6 +51,7 @@ 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; import net.pterodactylus.sone.core.event.MarkPostReplyKnownEvent; import net.pterodactylus.sone.core.event.MarkSoneKnownEvent; @@ -99,7 +100,6 @@ import net.pterodactylus.util.service.AbstractService; import net.pterodactylus.util.thread.NamedThreadFactory; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.HashMultimap; @@ -109,6 +109,7 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import com.google.inject.Singleton; +import kotlin.jvm.functions.Function1; /** * The Sone core. @@ -323,9 +324,10 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, return database.getSones(); } + @Nonnull @Override - public Function> soneLoader() { - return database.soneLoader(); + public Function1 getSoneLoader() { + return database.getSoneLoader(); } /** @@ -338,7 +340,8 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * Sone */ @Override - public Optional getSone(String id) { + @Nullable + public Sone getSone(@Nonnull String id) { return database.getSone(id); } @@ -358,9 +361,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * @return The Sone with the given ID, or {@code null} */ public Sone getLocalSone(String id) { - Optional sone = database.getSone(id); - if (sone.isPresent() && sone.get().isLocal()) { - return sone.get(); + Sone sone = database.getSone(id); + if ((sone != null) && sone.isLocal()) { + return sone; } return null; } @@ -382,7 +385,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * @return The Sone with the given ID */ public Sone getRemoteSone(String id) { - return database.getSone(id).orNull(); + return database.getSone(id); } /** @@ -420,11 +423,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, return database.newPostBuilder(); } - /** - * {@inheritDoc} - */ + @Nullable @Override - public Optional getPost(String postId) { + public Post getPost(@Nonnull String postId) { return database.getPost(postId); } @@ -457,8 +458,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, /** * {@inheritDoc} */ + @Nullable @Override - public Optional getPostReply(String replyId) { + public PostReply getPostReply(String replyId) { return database.getPostReply(replyId); } @@ -540,7 +542,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, */ @Nullable public Album getAlbum(@Nonnull String albumId) { - return database.getAlbum(albumId).orNull(); + return database.getAlbum(albumId); } public ImageBuilder imageBuilder() { @@ -573,9 +575,9 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, */ @Nullable public Image getImage(String imageId, boolean create) { - Optional image = database.getImage(imageId); - if (image.isPresent()) { - return image.get(); + Image image = database.getImage(imageId); + if (image != null) { + return image; } if (!create) { return null; @@ -653,6 +655,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, sone.setClient(new Client("Sone", SonePlugin.getPluginVersion())); sone.setKnown(true); SoneInserter soneInserter = new SoneInserter(this, eventBus, freenetInterface, ownIdentity.getId()); + soneInserter.insertionDelayChanged(new InsertionDelayChangedEvent(preferences.getInsertionDelay())); eventBus.register(soneInserter); synchronized (soneInserters) { soneInserters.put(sone, soneInserter); @@ -697,12 +700,12 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } String property = fromNullable(identity.getProperty("Sone.LatestEdition")).or("0"); long latestEdition = fromNullable(tryParse(property)).or(0L); - Optional existingSone = getSone(identity.getId()); - if (existingSone.isPresent() && existingSone.get().isLocal()) { - return existingSone.get(); + Sone existingSone = getSone(identity.getId()); + if ((existingSone != null )&& existingSone.isLocal()) { + return existingSone; } - boolean newSone = !existingSone.isPresent(); - Sone sone = !newSone ? existingSone.get() : database.newSoneBuilder().from(identity).build(); + boolean newSone = existingSone == null; + Sone sone = !newSone ? existingSone : database.newSoneBuilder().from(identity).build(); sone.setLatestEdition(latestEdition); if (newSone) { synchronized (knownSones) { @@ -740,16 +743,16 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, if (!soneFollowingTimes.containsKey(soneId)) { long now = System.currentTimeMillis(); soneFollowingTimes.put(soneId, now); - Optional followedSone = getSone(soneId); - if (!followedSone.isPresent()) { + Sone followedSone = getSone(soneId); + if (followedSone == null) { return; } - for (Post post : followedSone.get().getPosts()) { + for (Post post : followedSone.getPosts()) { if (post.getTime() < now) { markPostKnown(post); } } - for (PostReply reply : followedSone.get().getReplies()) { + for (PostReply reply : followedSone.getReplies()) { if (reply.getTime() < now) { markReplyKnown(reply); } @@ -874,20 +877,20 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * of the age of the given Sone */ public void updateSone(final Sone sone, boolean soneRescueMode) { - Optional storedSone = getSone(sone.getId()); - if (storedSone.isPresent()) { - if (!soneRescueMode && !(sone.getTime() > storedSone.get().getTime())) { + Sone storedSone = getSone(sone.getId()); + if (storedSone != null) { + if (!soneRescueMode && !(sone.getTime() > storedSone.getTime())) { logger.log(Level.FINE, String.format("Downloaded Sone %s is not newer than stored Sone %s.", sone, storedSone)); return; } List events = - collectEventsForChangesInSone(storedSone.get(), sone); + collectEventsForChangesInSone(storedSone, sone); database.storeSone(sone); for (Object event : events) { eventBus.post(event); } - sone.setOptions(storedSone.get().getOptions()); - sone.setKnown(storedSone.get().isKnown()); + sone.setOptions(storedSone.getOptions()); + sone.setKnown(storedSone.isKnown()); sone.setStatus((sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle); if (sone.isLocal()) { touchConfiguration(); @@ -1709,7 +1712,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, if (sone.isLocal()) { return; } - sone.setLatestEdition(fromNullable(tryParse(identity.getProperty("Sone.LatestEdition"))).or(sone.getLatestEdition())); + String newLatestEdition = identity.getProperty("Sone.LatestEdition"); + if (newLatestEdition != null) { + Long parsedNewLatestEdition = tryParse(newLatestEdition); + if (parsedNewLatestEdition != null) { + sone.setLatestEdition(parsedNewLatestEdition); + } + } soneDownloader.addSone(sone); soneDownloaders.execute(soneDownloader.fetchSoneAction(sone)); } @@ -1733,19 +1742,19 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, return; } } - Optional sone = getSone(identity.getId()); - if (!sone.isPresent()) { + Sone sone = getSone(identity.getId()); + if (sone == null) { /* TODO - we don’t have the Sone anymore. should this happen? */ return; } - for (PostReply postReply : sone.get().getReplies()) { + for (PostReply postReply : sone.getReplies()) { eventBus.post(new PostReplyRemovedEvent(postReply)); } - for (Post post : sone.get().getPosts()) { + for (Post post : sone.getPosts()) { eventBus.post(new PostRemovedEvent(post)); } - eventBus.post(new SoneRemovedEvent(sone.get())); - database.removeSone(sone.get()); + eventBus.post(new SoneRemovedEvent(sone)); + database.removeSone(sone); } /** diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java index 26135ea..3c32f7f 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java @@ -59,7 +59,6 @@ import net.pterodactylus.util.template.XmlFilter; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; -import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.Ordering; import com.google.common.eventbus.EventBus; @@ -125,20 +124,20 @@ public class SoneInserter extends AbstractService { this(core, eventBus, freenetInterface, soneId, new SoneModificationDetector(new LockableFingerprintProvider() { @Override public boolean isLocked() { - final Optional sone = core.getSone(soneId); - if (!sone.isPresent()) { + Sone sone = core.getSone(soneId); + if (sone == null) { return false; } - return core.isLocked(sone.get()); + return core.isLocked(sone); } @Override public String getFingerprint() { - final Optional sone = core.getSone(soneId); - if (!sone.isPresent()) { + Sone sone = core.getSone(soneId); + if (sone == null) { return null; } - return sone.get().getFingerprint(); + return sone.getFingerprint(); } }, insertionDelay), 1000); } @@ -219,12 +218,11 @@ public class SoneInserter extends AbstractService { sleep(delay); if (soneModificationDetector.isEligibleForInsert()) { - Optional soneOptional = core.getSone(soneId); - if (!soneOptional.isPresent()) { + Sone sone = core.getSone(soneId); + if (sone == null) { logger.log(Level.WARNING, format("Sone %s has disappeared, exiting inserter.", soneId)); return; } - Sone sone = soneOptional.get(); InsertInformation insertInformation = new InsertInformation(sone); logger.log(Level.INFO, String.format("Inserting Sone “%s”…", sone.getName())); diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java index 86f4098..2b785f9 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/PostImpl.java @@ -17,6 +17,8 @@ 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; @@ -99,7 +101,7 @@ public class PostImpl implements Post { */ @Override public Sone getSone() { - return soneProvider.getSone(soneId).get(); + return soneProvider.getSone(soneId); } /** @@ -107,7 +109,7 @@ public class PostImpl implements Post { */ @Override public Optional getRecipientId() { - return Optional.fromNullable(recipientId); + return fromNullable(recipientId); } /** @@ -115,7 +117,7 @@ public class PostImpl implements Post { */ @Override public Optional getRecipient() { - return soneProvider.getSone(recipientId); + return fromNullable(soneProvider.getSone(recipientId)); } /** diff --git a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java b/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java index 5084c1c..3571172 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/PostReplyImpl.java @@ -17,6 +17,8 @@ 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; @@ -78,7 +80,7 @@ public class PostReplyImpl extends ReplyImpl implements PostReply { */ @Override public Optional getPost() { - return postProvider.getPost(postId); + 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 index 4105749..372c80a 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/ReplyImpl.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/ReplyImpl.java @@ -83,7 +83,7 @@ public abstract class ReplyImpl> implements Reply { */ @Override public Sone getSone() { - return soneProvider.getSone(soneId).get(); + return soneProvider.getSone(soneId); } /** diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.java b/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.java deleted file mode 100644 index 2460306..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.java +++ /dev/null @@ -1,57 +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 {@link Album} objects. - * - * @author David ‘Bombe’ Roden - */ -public interface AlbumBuilder { - - /** - * Configures this builder to create an album with a random ID. - * - * @return This album builder - */ - AlbumBuilder randomId(); - - /** - * Configures this builder to create an album with the given ID. - * - * @param id - * The ID of the album - * @return This album builder - */ - AlbumBuilder withId(String id); - - AlbumBuilder by(Sone sone); - - /** - * Creates the album. - * - * @return The created album - * @throws IllegalStateException - * if the album could not be created - */ - Album build() throws IllegalStateException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt b/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt new file mode 100644 index 0000000..ed441e0 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/AlbumBuilder.kt @@ -0,0 +1,35 @@ +/* + * 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.java b/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.java deleted file mode 100644 index 07d7ae0..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.java +++ /dev/null @@ -1,34 +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 {@link AlbumBuilder}s. - * - * @author David ‘Bombe’ Roden - */ -public interface AlbumBuilderFactory { - - /** - * Creates a new album builder. - * - * @return A new album builder - */ - AlbumBuilder newAlbumBuilder(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt b/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt new file mode 100644 index 0000000..6f854db --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/AlbumBuilderFactory.kt @@ -0,0 +1,27 @@ +/* + * 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.java b/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.java deleted file mode 100644 index 8e6fa45..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.java +++ /dev/null @@ -1,30 +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 {@link AlbumProvider} and an {@link AlbumStore} into an album - * database. - * - * @author David ‘Bombe’ Roden - */ -public interface AlbumDatabase extends AlbumProvider, AlbumBuilderFactory, AlbumStore { - - /* nothing here. */ - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt b/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt new file mode 100644 index 0000000..69daa21 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/AlbumDatabase.kt @@ -0,0 +1,24 @@ +/* + * 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.java b/src/main/java/net/pterodactylus/sone/database/AlbumProvider.java deleted file mode 100644 index 746f014..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumProvider.java +++ /dev/null @@ -1,41 +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 {@link Album}s by their ID. - * - * @author David ‘Bombe’ Roden - */ -public interface AlbumProvider { - - /** - * Returns the album with the given ID, or {@link Optional#absent()} if no such - * album exists. - * - * @param albumId - * The ID of the album - * @return The album, or {@link Optional#absent()} if the album does not exist - */ - Optional getAlbum(String albumId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt b/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt new file mode 100644 index 0000000..c0b09e8 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/AlbumProvider.kt @@ -0,0 +1,31 @@ +/* + * 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.java b/src/main/java/net/pterodactylus/sone/database/AlbumStore.java deleted file mode 100644 index 2a9bfd0..0000000 --- a/src/main/java/net/pterodactylus/sone/database/AlbumStore.java +++ /dev/null @@ -1,45 +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. - * - * @author David ‘Bombe’ Roden - */ -public interface AlbumStore { - - /** - * Stores the given album. - * - * @param album - * The album to store - */ - void storeAlbum(Album album); - - /** - * Removes the given album from the store. - * - * @param album - * The album to remove - */ - void removeAlbum(Album album); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt b/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt new file mode 100644 index 0000000..e2a31c7 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/database/AlbumStore.kt @@ -0,0 +1,30 @@ +/* + * 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/BookmarkDatabase.java b/src/main/java/net/pterodactylus/sone/database/BookmarkDatabase.java deleted file mode 100644 index 6eb9c38..0000000 --- a/src/main/java/net/pterodactylus/sone/database/BookmarkDatabase.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.pterodactylus.sone.database; - -import java.util.Set; - -import net.pterodactylus.sone.data.Post; - -/** - * Database interface for bookmark-related functionality. - * - * @author David ‘Bombe’ Roden - */ -public interface BookmarkDatabase { - - void bookmarkPost(Post post); - void unbookmarkPost(Post post); - boolean isPostBookmarked(Post post); - Set getBookmarkedPosts(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/Database.java b/src/main/java/net/pterodactylus/sone/database/Database.java deleted file mode 100644 index db63ba3..0000000 --- a/src/main/java/net/pterodactylus/sone/database/Database.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Sone - Database.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.database.memory.MemoryDatabase; - -import com.google.common.util.concurrent.Service; -import com.google.inject.ImplementedBy; - -/** - * Database for Sone data. This interface combines the various provider, - * store, and builder factory interfaces into a single interface. - * - * @author David ‘Bombe’ Roden - */ -@ImplementedBy(MemoryDatabase.class) -public interface Database extends Service, SoneDatabase, FriendDatabase, PostDatabase, PostReplyDatabase, AlbumDatabase, ImageDatabase, BookmarkDatabase { - - /** - * Saves the database. - * - * @throws DatabaseException - * if an error occurs while saving - */ - public void save() throws DatabaseException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/FriendDatabase.java b/src/main/java/net/pterodactylus/sone/database/FriendDatabase.java deleted file mode 100644 index 761d356..0000000 --- a/src/main/java/net/pterodactylus/sone/database/FriendDatabase.java +++ /dev/null @@ -1,10 +0,0 @@ -package net.pterodactylus.sone.database; - -/** - * Combines a {@link FriendProvider} and a {@link FriendStore} into a friend database. - * - * @author David ‘Bombe’ Roden - */ -public interface FriendDatabase extends FriendProvider, FriendStore { - -} diff --git a/src/main/java/net/pterodactylus/sone/database/FriendProvider.java b/src/main/java/net/pterodactylus/sone/database/FriendProvider.java deleted file mode 100644 index 3665d1b..0000000 --- a/src/main/java/net/pterodactylus/sone/database/FriendProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.pterodactylus.sone.database; - -import java.util.Collection; - -import net.pterodactylus.sone.data.Sone; - -/** - * Provides information about {@link Sone#getFriends() friends} of a {@link Sone}. - * - * @author David ‘Bombe’ Roden - */ -public interface FriendProvider { - - Collection getFriends(Sone localSone); - boolean isFriend(Sone localSone, String friendSoneId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/FriendStore.java b/src/main/java/net/pterodactylus/sone/database/FriendStore.java deleted file mode 100644 index 38c1c80..0000000 --- a/src/main/java/net/pterodactylus/sone/database/FriendStore.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.pterodactylus.sone.database; - -import net.pterodactylus.sone.data.Sone; - -/** - * Stores information about the {@link Sone#getFriends() friends} of a {@link Sone}. - * - * @author David ‘Bombe’ Roden - */ -public interface FriendStore { - - void addFriend(Sone localSone, String friendSoneId); - void removeFriend(Sone localSone, String friendSoneId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ImageBuilder.java b/src/main/java/net/pterodactylus/sone/database/ImageBuilder.java deleted file mode 100644 index 7b5c9e0..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ImageBuilder.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Sone - ImageBuilder.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.Image; - -/** - * Builder for {@link Image} objects. - * - * @author David Roden - */ -public interface ImageBuilder { - - ImageBuilder randomId(); - - ImageBuilder withId(String id); - - Image build() throws IllegalStateException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ImageBuilderFactory.java b/src/main/java/net/pterodactylus/sone/database/ImageBuilderFactory.java deleted file mode 100644 index 900c989..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ImageBuilderFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Sone - ImageBuilderFactory.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 {@link ImageBuilder}s. - * - * @author David Roden - */ -public interface ImageBuilderFactory { - - ImageBuilder newImageBuilder(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ImageDatabase.java b/src/main/java/net/pterodactylus/sone/database/ImageDatabase.java deleted file mode 100644 index 090aa3b..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ImageDatabase.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Sone - ImageDatabase.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 {@link ImageProvider}, an {@link ImageBuilderFactory}, and an - * {@link ImageStore} into an image database. - * - * @author David ‘Bombe’ Roden - */ -public interface ImageDatabase extends ImageProvider, ImageBuilderFactory, ImageStore { - - /* nothing here. */ - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ImageProvider.java b/src/main/java/net/pterodactylus/sone/database/ImageProvider.java deleted file mode 100644 index 8ee3e5f..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ImageProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Sone - ImageProvider.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.Image; - -import com.google.common.base.Optional; - -/** - * Provides {@link Image}. - * - * @author David Roden - */ -public interface ImageProvider { - - Optional getImage(String imageId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ImageStore.java b/src/main/java/net/pterodactylus/sone/database/ImageStore.java deleted file mode 100644 index 97a7240..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ImageStore.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Sone - ImageStore.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.Image; - -/** - * Manages {@link Image} storage. - * - * @author David Roden - */ -public interface ImageStore { - - void storeImage(Image image); - - void removeImage(Image image); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostBuilder.java b/src/main/java/net/pterodactylus/sone/database/PostBuilder.java deleted file mode 100644 index 45cc062..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostBuilder.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Sone - PostBuilder.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.Post; -import net.pterodactylus.sone.data.Sone; - -/** - * Builder for {@link Post} objects. - *

- * A {@link Post} consists of the following elements: - *

    - *
  • an ID,
  • - *
  • a {@link Sone sender},
  • - *
  • an optional {@link Sone recipient},
  • - *
  • a time,
  • - *
  • and a text.
  • - *
- * Except for the recipient, all this elements have to be configured on this - * builder. For the ID you have the possibility to configure either a random ID - * (which should be used for new posts) or a custom ID you specify (for creating - * an existing post). For the time you can use the current time (again, for - * creating new posts) or the given time (for loading posts). It is an error to - * specify both ways for either the ID or the time. - * - * @author David ‘Bombe’ Roden - */ -public interface PostBuilder { - - /** - * Copies all attributes of the given post to this post builder. - * - * @param post - * The post whose attributes to copy into this builder - * @return This builder - * @throws NullPointerException - * if {@code post} is {@code null} - */ - public PostBuilder copyPost(Post post) throws NullPointerException; - - /** - * Configures this builder to use the given Sone as sender of the new post. - * - * @param senderId - * The ID of the sender of the post - * @return This post builder - */ - public PostBuilder from(String senderId); - - /** - * Configures this builder to use a random ID for the new post. If this - * method is used, {@link #withId(String)} must not be used. - * - * @return This post builder - */ - public PostBuilder randomId(); - - /** - * Configures this builder to use the given ID as ID for the new post. If - * this method is used, {@link #randomId()} must not be used. - * - * @param id - * The ID to use for the post - * @return This post builder - */ - public PostBuilder withId(String id); - - /** - * Configures this builder to use the current time when creating the post. - * If this method is used, {@link #withTime(long)} must not be used. - * - * @return This post builder - */ - public PostBuilder currentTime(); - - /** - * Configures the builder to use the given time as time for the new post. If - * this method is used, {@link #currentTime()} must not be used. - * - * @param time - * The time to use for the post - * @return This post builder - */ - public PostBuilder withTime(long time); - - /** - * Configures the builder to use the given text for the new post. - * - * @param text - * The text to use for the post - * @return This post builder - */ - public PostBuilder withText(String text); - - /** - * Configures the builder to use the given {@link Sone} as recipient for the - * post. - * - * @param recipientId - * The ID of the recipient of the post - * @return This post builder - */ - public PostBuilder to(String recipientId); - - /** - * Verifies this builder’s configuration and creates a new post. - *

- * The following conditions must be met in order for this builder to be - * configured correctly: - *

    - *
  • Exactly one of {@link #randomId()} or {@link #withId(String)} must - * have been called.
  • - *
  • The {@link #from(String) sender} must not be {@code null}.
  • - *
  • Exactly one of {@link #currentTime()} or {@link #withTime(long)} must - * have been called.
  • - *
  • The {@link #withText(String) text} must not be {@code null} and must - * contain something other than whitespace.
  • - *
  • The {@link #to(String) recipient} must either not have been set, or - * it must have been set to a {@link Sone} other than {@link #from(String) - * the sender}.
  • - *
- * - * @return A new post - * @throws IllegalStateException - * if this builder’s configuration is not valid - */ - public Post build() throws IllegalStateException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostBuilderFactory.java b/src/main/java/net/pterodactylus/sone/database/PostBuilderFactory.java deleted file mode 100644 index e5cee38..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostBuilderFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - PostBuilderFactory.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.database.memory.MemoryDatabase; - -import com.google.inject.ImplementedBy; - -/** - * Factory for {@link PostBuilder}s. - * - * @author David ‘Bombe’ Roden - */ -@ImplementedBy(MemoryDatabase.class) -public interface PostBuilderFactory { - - /** - * Creates a new post builder. - * - * @return A new post builder - */ - public PostBuilder newPostBuilder(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostDatabase.java b/src/main/java/net/pterodactylus/sone/database/PostDatabase.java deleted file mode 100644 index 648c77e..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostDatabase.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Sone - PostDatabase.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 a {@link PostProvider}, a {@link PostBuilderFactory}, and a - * {@link PostStore} into a complete post database. - * - * @author David ‘Bombe’ Roden - */ -public interface PostDatabase extends PostProvider, PostBuilderFactory, PostStore { - - /* nothing here. */ - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostProvider.java b/src/main/java/net/pterodactylus/sone/database/PostProvider.java deleted file mode 100644 index bea59b9..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Sone - PostProvider.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.database; - -import java.util.Collection; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.database.memory.MemoryDatabase; - -import com.google.common.base.Optional; -import com.google.inject.ImplementedBy; - -/** - * Interface for objects that can provide {@link Post}s by their ID. - * - * @author David ‘Bombe’ Roden - */ -@ImplementedBy(MemoryDatabase.class) -public interface PostProvider { - - /** - * Returns the post with the given ID. - * - * @param postId - * The ID of the post to return - * @return The post with the given ID, or {@code null} - */ - public Optional getPost(String postId); - - /** - * Returns all posts from the given Sone. - * - * @param soneId - * The ID of the Sone - * @return All posts from the given Sone - */ - public Collection getPosts(String soneId); - - /** - * Returns all posts that have the given Sone as recipient. - * - * @see Post#getRecipient() - * @param recipientId - * The ID of the recipient of the posts - * @return All posts that have the given Sone as recipient - */ - public Collection getDirectedPosts(String recipientId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyBuilder.java b/src/main/java/net/pterodactylus/sone/database/PostReplyBuilder.java deleted file mode 100644 index 16569d9..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyBuilder.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Sone - PostReplyBuilder.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.PostReply; - -/** - * Builder for a {@link PostReply} object. - * - * @author David ‘Bombe’ Roden - */ -public interface PostReplyBuilder extends ReplyBuilder { - - /** - * Configures this builder to set the given post as post the created reply - * refers to. - * - * @param postId - * The ID of the post the reply refers to - * @return This builder - */ - public PostReplyBuilder to(String postId); - - /** - * Verifies the configuration of this builder and creates a new post reply. - *

- * The following conditions must be met in order for the configuration to be - * considered valid: - *

    - *
  • Exactly one of {@link #randomId()} or {@link #withId(String)} must - * have been called.
  • - *
  • The {@link #from(String) sender} must not be {@code null}.
  • - *
  • Exactly one of {@link #currentTime()} or {@link #withTime(long)} must - * have been called.
  • - *
  • The {@link #withText(String) text} must not be {@code null} and must - * contain something other than whitespace.
  • - *
  • The {@link #to(String) post} have been set.
  • - *
- * - * @return The created post reply - * @throws IllegalStateException - * if this builder’s configuration is not valid - */ - public PostReply build() throws IllegalStateException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyBuilderFactory.java b/src/main/java/net/pterodactylus/sone/database/PostReplyBuilderFactory.java deleted file mode 100644 index f85b18b..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyBuilderFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Sone - PostReplyBuilderFactory.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.database.memory.MemoryDatabase; - -import com.google.inject.ImplementedBy; - -/** - * Factory for {@link PostReplyBuilder}s. - * - * @author David ‘Bombe’ Roden - */ -@ImplementedBy(MemoryDatabase.class) -public interface PostReplyBuilderFactory { - - /** - * Creates a new post reply builder. - * - * @return A new post reply builder - */ - public PostReplyBuilder newPostReplyBuilder(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java b/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java deleted file mode 100644 index f226d73..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Sone - PostReplyDatabase.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 a {@link PostReplyProvider}, a {@link PostReplyBuilderFactory}, and - * a {@link PostReplyStore} into a complete post reply database. - * - * @author David ‘Bombe’ Roden - */ -public interface PostReplyDatabase extends PostReplyProvider, PostReplyBuilderFactory, PostReplyStore { - - /* nothing here. */ - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyProvider.java b/src/main/java/net/pterodactylus/sone/database/PostReplyProvider.java deleted file mode 100644 index e982599..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Sone - PostReplyProvider.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 java.util.List; - -import net.pterodactylus.sone.data.PostReply; - -import com.google.common.base.Optional; - -/** - * Interface for objects that can provide {@link PostReply}s. - * - * @author David ‘Bombe’ Roden - */ -public interface PostReplyProvider { - - /** - * Returns the reply with the given ID. - * - * @param id - * The ID of the reply to get - * @return The reply, or {@code null} if there is no such reply - */ - public Optional getPostReply(String id); - - /** - * Returns all replies for the given post, order ascending by time. - * - * @param postId - * The ID of the post to get all replies for - * @return All replies for the given post - */ - public List getReplies(String postId); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyStore.java b/src/main/java/net/pterodactylus/sone/database/PostReplyStore.java deleted file mode 100644 index 7956a92..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyStore.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Sone - PostReplyStore.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 java.util.Collection; - -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -/** - * Defines a store for {@link PostReply post replies}. - * - * @author David ‘Bombe’ Roden - */ -public interface PostReplyStore { - - /** - * Stores the given post reply. - * - * @param postReply - * The post reply - */ - public void storePostReply(PostReply postReply); - - /** - * Removes the given post reply from this store. - * - * @param postReply - * The post reply to remove - */ - public void removePostReply(PostReply postReply); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/PostStore.java b/src/main/java/net/pterodactylus/sone/database/PostStore.java deleted file mode 100644 index 7c3e07f..0000000 --- a/src/main/java/net/pterodactylus/sone/database/PostStore.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Sone - PostStore.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 java.util.Collection; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Sone; - -/** - * Interface for a store for posts. - * - * @author David ‘Bombe’ Roden - */ -public interface PostStore { - - /** - * Adds the given post to the store. - * - * @param post - * The post to store - */ - public void storePost(Post post); - - /** - * Removes the given post. - * - * @param post - * The post to remove - */ - public void removePost(Post post); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/ReplyBuilder.java b/src/main/java/net/pterodactylus/sone/database/ReplyBuilder.java deleted file mode 100644 index 21ba89c..0000000 --- a/src/main/java/net/pterodactylus/sone/database/ReplyBuilder.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Sone - ReplyBuilder.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.Reply; -import net.pterodactylus.sone.data.Sone; - -/** - * Methods that all reply builders need to implement in order to be able to - * create any kind of {@link Reply}. - * - * @param - * The type of the builder - * @author David ‘Bombe’ Roden - */ -public interface ReplyBuilder> { - - /** - * Configures this builder to use a random ID when creating the reply. If - * this method is used, {@link #withId(String)} must not be used. - * - * @return This builder - */ - public B randomId(); - - /** - * Configures this builder to use the given ID when creating the reply. If - * this method is used, {@link #randomId()} must not be used. - * - * @param id - * The ID of the reply - * @return This builder - */ - public B withId(String id); - - /** - * Configures this builder to use the ID of the given {@link Sone} as sender - * of the reply. - * - * @param senderId - * The ID of the sender of the reply - * @return This builder - */ - public B from(String senderId); - - /** - * Configures this builder to use the current time when creating the reply. - * If this method is used, {@link #withTime(long)} must not be used. - * - * @return This builder - */ - public B currentTime(); - - /** - * Configures this builder to use the given time when creating the reply. If - * this method is used, {@link #currentTime()} must not be used. - * - * @param time - * The time of the reply - * @return This builder - */ - public B withTime(long time); - - /** - * Configures this builder to use the given text when creating the reply. - * - * @param text - * The text of the reply - * @return This builder - */ - public B withText(String text); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneBuilder.java b/src/main/java/net/pterodactylus/sone/database/SoneBuilder.java deleted file mode 100644 index d2047af..0000000 --- a/src/main/java/net/pterodactylus/sone/database/SoneBuilder.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.pterodactylus.sone.database; - -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.freenet.wot.Identity; - -/** - * Builder for {@link Sone} objects. - * - * @author David ‘Bombe’ Roden - */ -public interface SoneBuilder { - - SoneBuilder from(Identity identity); - SoneBuilder local(); - - Sone build() throws IllegalStateException; - -} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneBuilderFactory.java b/src/main/java/net/pterodactylus/sone/database/SoneBuilderFactory.java deleted file mode 100644 index c95251f..0000000 --- a/src/main/java/net/pterodactylus/sone/database/SoneBuilderFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.pterodactylus.sone.database; - -/** - * Factory for {@link SoneBuilder}s. - * - * @author David ‘Bombe’ Roden - */ -public interface SoneBuilderFactory { - - SoneBuilder newSoneBuilder(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java b/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java deleted file mode 100644 index f5c5cda..0000000 --- a/src/main/java/net/pterodactylus/sone/database/SoneDatabase.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.pterodactylus.sone.database; - -/** - * Combines a {@link SoneProvider} and a {@link SoneStore} into a Sone - * database. - * - * @author David ‘Bombe’ Roden - */ -public interface SoneDatabase extends SoneProvider, SoneBuilderFactory, SoneStore { - -} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneProvider.java b/src/main/java/net/pterodactylus/sone/database/SoneProvider.java deleted file mode 100644 index 69f7eaf..0000000 --- a/src/main/java/net/pterodactylus/sone/database/SoneProvider.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Sone - SoneProvider.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.database; - -import java.util.Collection; - -import javax.annotation.Nonnull; - -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; - -/** - * Interface for objects that can provide {@link Sone}s by their ID. - * - * @author David ‘Bombe’ Roden - */ -@ImplementedBy(Core.class) -public interface SoneProvider { - - Function> soneLoader(); - - /** - * Returns the Sone with the given ID, or {@link Optional#absent()} if it - * does not exist. - * - * @param soneId - * The ID of the Sone to return - * @return The Sone with the given ID, or {@link Optional#absent()} - */ - public Optional getSone(String soneId); - - /** - * Returns all Sones. - * - * @return All Sones - */ - @Nonnull - public Collection getSones(); - - /** - * Returns all local Sones. - * - * @return All local Sones - */ - public Collection getLocalSones(); - - /** - * Returns all remote Sones. - * - * @return All remote Sones - */ - public Collection getRemoteSones(); - -} diff --git a/src/main/java/net/pterodactylus/sone/database/SoneStore.java b/src/main/java/net/pterodactylus/sone/database/SoneStore.java deleted file mode 100644 index 3684d48..0000000 --- a/src/main/java/net/pterodactylus/sone/database/SoneStore.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.pterodactylus.sone.database; - -import net.pterodactylus.sone.data.Sone; - -/** - * Interface for a store for {@link Sone}s. - * - * @author David ‘Bombe’ Roden - */ -public interface SoneStore { - - void storeSone(Sone sone); - void removeSone(Sone sone); - -} 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 594cf2b..4c4bc3f 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabase.java @@ -1,5 +1,6 @@ package net.pterodactylus.sone.database.memory; +import static com.google.common.base.Optional.fromNullable; import static com.google.common.collect.FluentIterable.from; import java.util.HashSet; @@ -99,7 +100,7 @@ public class MemoryBookmarkDatabase implements BookmarkDatabase { new Function() { @Override public Post apply(String postId) { - return memoryDatabase.getPost(postId) + return fromNullable(memoryDatabase.getPost(postId)) .or(new EmptyPost(postId)); } }).toSet(); diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java index aa4a2a8..5e5021c 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -37,6 +37,9 @@ 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; @@ -56,8 +59,6 @@ import net.pterodactylus.sone.database.SoneProvider; import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; @@ -66,6 +67,7 @@ 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. @@ -241,21 +243,22 @@ public class MemoryDatabase extends AbstractService implements Database { } } + @Nonnull @Override - public Function> soneLoader() { - return new Function>() { + public Function1 getSoneLoader() { + return new Function1() { @Override - public Optional apply(String soneId) { + public Sone invoke(String soneId) { return getSone(soneId); } }; } @Override - public Optional getSone(String soneId) { + public Sone getSone(String soneId) { lock.readLock().lock(); try { - return fromNullable(allSones.get(soneId)); + return allSones.get(soneId); } finally { lock.readLock().unlock(); } @@ -328,12 +331,12 @@ public class MemoryDatabase extends AbstractService implements Database { // POSTPROVIDER METHODS // - /** {@inheritDocs} */ + @Nullable @Override - public Optional getPost(String postId) { + public Post getPost(@Nonnull String postId) { lock.readLock().lock(); try { - return fromNullable(allPosts.get(postId)); + return allPosts.get(postId); } finally { lock.readLock().unlock(); } @@ -406,12 +409,12 @@ public class MemoryDatabase extends AbstractService implements Database { // POSTREPLYPROVIDER METHODS // - /** {@inheritDocs} */ + @Nullable @Override - public Optional getPostReply(String id) { + public PostReply getPostReply(String id) { lock.readLock().lock(); try { - return fromNullable(allPostReplies.get(id)); + return allPostReplies.get(id); } finally { lock.readLock().unlock(); } @@ -474,11 +477,12 @@ public class MemoryDatabase extends AbstractService implements Database { // ALBUMPROVDER METHODS // + @Nullable @Override - public Optional getAlbum(String albumId) { + public Album getAlbum(@Nonnull String albumId) { lock.readLock().lock(); try { - return fromNullable(allAlbums.get(albumId)); + return allAlbums.get(albumId); } finally { lock.readLock().unlock(); } @@ -523,11 +527,12 @@ public class MemoryDatabase extends AbstractService implements Database { // IMAGEPROVIDER METHODS // + @Nullable @Override - public Optional getImage(String imageId) { + public Image getImage(@Nonnull String imageId) { lock.readLock().lock(); try { - return fromNullable(allImages.get(imageId)); + return allImages.get(imageId); } finally { lock.readLock().unlock(); } 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 acf2374..724c627 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPost.java @@ -17,6 +17,8 @@ package net.pterodactylus.sone.database.memory; +import static com.google.common.base.Optional.fromNullable; + import java.util.UUID; import net.pterodactylus.sone.data.Post; @@ -104,7 +106,7 @@ class MemoryPost implements Post { */ @Override public Sone getSone() { - return soneProvider.getSone(soneId).get(); + return soneProvider.getSone(soneId); } /** @@ -112,7 +114,7 @@ class MemoryPost implements Post { */ @Override public Optional getRecipientId() { - return Optional.fromNullable(recipientId); + return fromNullable(recipientId); } /** @@ -120,7 +122,7 @@ class MemoryPost implements Post { */ @Override public Optional getRecipient() { - return soneProvider.getSone(recipientId); + return fromNullable(soneProvider.getSone(recipientId)); } /** 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 714b84e..687c28a 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryPostReply.java @@ -17,6 +17,8 @@ package net.pterodactylus.sone.database.memory; +import static com.google.common.base.Optional.fromNullable; + import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; @@ -97,7 +99,7 @@ class MemoryPostReply implements PostReply { */ @Override public Sone getSone() { - return soneProvider.getSone(soneId).get(); + return soneProvider.getSone(soneId); } /** @@ -150,7 +152,7 @@ class MemoryPostReply implements PostReply { */ @Override public Optional getPost() { - return database.getPost(postId); + return fromNullable(database.getPost(postId)); } // diff --git a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java index 98a43ab..9942af7 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java @@ -161,11 +161,11 @@ public abstract class AbstractSoneCommand extends AbstractCommand { if (mandatory && (soneId == null)) { throw new FcpException("Could not load Sone ID from “" + parameterName + "”."); } - Optional sone = core.getSone(soneId); - if ((mandatory && !sone.isPresent()) || (sone.isPresent() && localOnly && !sone.get().isLocal())) { + Sone sone = core.getSone(soneId); + if ((mandatory && (sone == null)) || ((sone != null) && localOnly && !sone.isLocal())) { throw new FcpException("Could not load Sone from “" + soneId + "”."); } - return sone; + return Optional.fromNullable(sone); } /** @@ -184,11 +184,11 @@ public abstract class AbstractSoneCommand extends AbstractCommand { protected Post getPost(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { try { String postId = simpleFieldSet.getString(parameterName); - Optional post = core.getPost(postId); - if (!post.isPresent()) { + Post post = core.getPost(postId); + if (post == null) { throw new FcpException("Could not load post from “" + postId + "”."); } - return post.get(); + return post; } catch (FSParseException fspe1) { throw new FcpException("Could not post ID from “" + parameterName + "”.", fspe1); } @@ -210,11 +210,11 @@ public abstract class AbstractSoneCommand extends AbstractCommand { protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { try { String replyId = simpleFieldSet.getString(parameterName); - Optional reply = core.getPostReply(replyId); - if (!reply.isPresent()) { + PostReply reply = core.getPostReply(replyId); + if (reply == null) { throw new FcpException("Could not load reply from “" + replyId + "”."); } - return reply.get(); + return reply; } catch (FSParseException fspe1) { throw new FcpException("Could not reply ID from “" + parameterName + "”.", fspe1); } diff --git a/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java b/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java index 7b804fb..4ee15e3 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/GetPostFeedCommand.java @@ -28,7 +28,6 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.fcp.FcpException; -import com.google.common.base.Optional; import com.google.common.collect.Collections2; import freenet.support.SimpleFieldSet; @@ -63,11 +62,11 @@ public class GetPostFeedCommand extends AbstractSoneCommand { Collection allPosts = new HashSet(); allPosts.addAll(sone.getPosts()); for (String friendSoneId : sone.getFriends()) { - Optional friendSone = getCore().getSone(friendSoneId); - if (!friendSone.isPresent()) { + Sone friendSone = getCore().getSone(friendSoneId); + if (friendSone == null) { continue; } - allPosts.addAll(friendSone.get().getPosts()); + allPosts.addAll(friendSone.getPosts()); } allPosts.addAll(getCore().getDirectedPosts(sone.getId())); allPosts = Collections2.filter(allPosts, Post.FUTURE_POSTS_FILTER); diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index c1628eb..5cf708f 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -26,7 +26,11 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import javax.inject.Singleton; + import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.database.Database; +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; @@ -117,7 +121,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr /** The current year at time of release. */ private static final int YEAR = 2017; private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/"; - private static final int LATEST_EDITION = 76; + private static final int LATEST_EDITION = 77; /** The logger. */ private static final Logger logger = getLogger(SonePlugin.class.getName()); @@ -252,6 +256,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr bind(PluginVersion.class).toInstance(new PluginVersion(getVersion())); bind(PluginYear.class).toInstance(new PluginYear(getYear())); bind(PluginHomepage.class).toInstance(new PluginHomepage(getHomepage())); + bind(Database.class).to(MemoryDatabase.class).in(Singleton.class); if (startConfiguration.getBooleanValue("Developer.LoadFromFilesystem").getValue(false)) { String path = startConfiguration.getStringValue("Developer.FilesystemPath").getValue(null); if (path != null) { diff --git a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java b/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java deleted file mode 100644 index 39d26db..0000000 --- a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Sone - SoneTextParser.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.text; - -import static com.google.common.base.Optional.absent; -import static com.google.common.base.Optional.of; -import static java.util.logging.Logger.getLogger; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -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 org.bitpedia.util.Base32; - -import freenet.keys.FreenetURI; -import freenet.support.Base64; - -/** - * {@link Parser} implementation that can recognize Freenet URIs. - * - * @author David ‘Bombe’ Roden - */ -public class SoneTextParser implements Parser { - - /** The logger. */ - private static final Logger logger = getLogger(SoneTextParser.class.getName()); - - /** Pattern to detect whitespace. */ - private static final Pattern whitespacePattern = Pattern.compile("[\\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 static class NextLink { - - private final int position; - private final String link; - private final String remainder; - private final LinkType linkType; - - private NextLink(int position, String link, String remainder, LinkType linkType) { - this.position = position; - this.link = link; - this.remainder = remainder; - this.linkType = linkType; - } - - public int getPosition() { - return position; - } - - public String getLink() { - return link; - } - - public String getRemainder() { - return remainder; - } - - public LinkType getLinkType() { - return linkType; - } - - } - - /** - * Enumeration for all recognized link types. - * - * @author David ‘Bombe’ Roden - */ - private enum LinkType { - - KSK("KSK@", true), - CHK("CHK@", true), - SSK("SSK@", true), - USK("USK@", true), - HTTP("http://", false), - HTTPS("https://", false), - SONE("sone://", false), - POST("post://", false), - - FREEMAIL("", true) { - @Override - public Optional findNext(String line) { - int nextFreemailSuffix = line.indexOf(".freemail"); - if (nextFreemailSuffix < 54) { - /* 52 chars for the id, 1 on @, at least 1 for the local part. */ - return absent(); - } - if (line.charAt(nextFreemailSuffix - 53) != '@') { - return absent(); - } - if (!line.substring(nextFreemailSuffix - 52, nextFreemailSuffix).matches("^[a-z2-7]*$")) { - return absent(); - } - int startOfLocalPart = nextFreemailSuffix - 54; - if (!isAllowedInLocalPart(line.charAt(startOfLocalPart))) { - return absent(); - } - while ((startOfLocalPart > 0) && isAllowedInLocalPart(line.charAt(startOfLocalPart - 1))) { - startOfLocalPart--; - } - return of(new NextLink(startOfLocalPart, line.substring(startOfLocalPart, nextFreemailSuffix + 9), line.substring(nextFreemailSuffix + 9), this)); - } - - private boolean isAllowedInLocalPart(char character) { - return ((character >= 'A') && (character <= 'Z')) - || ((character >= 'a') && (character <= 'z')) - || ((character >= '0') && (character <= '9')) - || (character == '.') || (character == '-') || (character == '_'); - } - }; - - private final String scheme; - private final boolean freenetLink; - - LinkType(String scheme, boolean freenetLink) { - this.scheme = scheme; - this.freenetLink = freenetLink; - } - - /** - * Returns the scheme of this link type. - * - * @return The scheme of this link type - */ - public String getScheme() { - return scheme; - } - - public boolean isFreenetLink() { - return freenetLink; - } - - public Optional findNext(String line) { - int nextLinkPosition = line.indexOf(getScheme()); - if (nextLinkPosition == -1) { - return absent(); - } - int endOfLink = findEndOfLink(line.substring(nextLinkPosition)); - return of(new NextLink(nextLinkPosition, line.substring(nextLinkPosition, nextLinkPosition + endOfLink), line.substring(nextLinkPosition + endOfLink), this)); - } - - private static int findEndOfLink(String line) { - Matcher matcher = whitespacePattern.matcher(line); - int endOfLink = matcher.find() ? matcher.start() : line.length(); - while (isPunctuation(line.charAt(endOfLink - 1))) { - endOfLink--; - } - int openParens = 0; - for (int i = 0; i < endOfLink; i++) { - switch (line.charAt(i)) { - case '(': - openParens++; - break; - case ')': - openParens--; - if (openParens < 0) { - return i; - } - default: - } - } - return endOfLink; - } - - } - - /** The Sone provider. */ - private final SoneProvider soneProvider; - - /** The post provider. */ - private final PostProvider postProvider; - - /** - * Creates a new freenet link parser. - * - * @param soneProvider - * The Sone provider - * @param postProvider - * The post provider - */ - public SoneTextParser(SoneProvider soneProvider, PostProvider postProvider) { - this.soneProvider = soneProvider; - this.postProvider = postProvider; - } - - // - // PART METHODS - // - - /** - * {@inheritDoc} - */ - @Nonnull - @Override - public Iterable parse(@Nonnull String source, @Nullable SoneTextParserContext context) { - List parts = new ArrayList<>(); - try (Reader sourceReader = new StringReader(source); - BufferedReader bufferedReader = new BufferedReader(sourceReader)) { - String line; - boolean lastLineEmpty = true; - int emptyLines = 0; - while ((line = bufferedReader.readLine()) != null) { - if (line.trim().length() == 0) { - if (lastLineEmpty) { - continue; - } - parts.add(new PlainTextPart("\n")); - ++emptyLines; - lastLineEmpty = emptyLines == 2; - continue; - } - emptyLines = 0; - /* - * lineComplete tracks whether the block you are parsing is the - * first block of the line. this is important because sometimes - * you have to add an additional line break. - */ - boolean lineComplete = true; - while (line.length() > 0) { - Optional nextLink = findNextLink(line); - if (!nextLink.isPresent()) { - if (lineComplete && !lastLineEmpty) { - parts.add(new PlainTextPart("\n" + line)); - } else { - parts.add(new PlainTextPart(line)); - } - break; - } - LinkType linkType = nextLink.get().getLinkType(); - int next = nextLink.get().getPosition(); - - /* cut off “freenet:” from before keys. */ - if (linkType.isFreenetLink() && (next >= 8) && (line.substring(next - 8, next).equals("freenet:"))) { - next -= 8; - line = line.substring(0, next) + line.substring(next + 8); - } - - /* if there is text before the next item, write it out. */ - if (lineComplete && !lastLineEmpty) { - parts.add(new PlainTextPart("\n")); - } - if (next > 0) { - parts.add(new PlainTextPart(line.substring(0, next))); - line = line.substring(next); - } - lineComplete = false; - - String link = nextLink.get().getLink(); - logger.log(Level.FINER, String.format("Found link: %s", link)); - - /* if there is no text after the scheme, it’s not a link! */ - if (link.equals(linkType.getScheme())) { - parts.add(new PlainTextPart(linkType.getScheme())); - line = line.substring(linkType.getScheme().length()); - continue; - } - - switch (linkType) { - case SONE: - renderSoneLink(parts, link); - break; - case POST: - renderPostLink(parts, link); - break; - case KSK: - case CHK: - case SSK: - case USK: - renderFreenetLink(parts, link, linkType, context); - break; - case HTTP: - case HTTPS: - renderHttpLink(parts, link, linkType); - break; - case FREEMAIL: - renderFreemailLink(parts, link); - } - - line = nextLink.get().getRemainder(); - } - lastLineEmpty = false; - } - } catch (IOException ioe1) { - // a buffered reader around a string reader should never throw. - throw new RuntimeException(ioe1); - } - for (int partIndex = parts.size() - 1; partIndex >= 0; --partIndex) { - Part part = parts.get(partIndex); - if (!(part instanceof PlainTextPart) || !"\n".equals(part.getText())) { - break; - } - parts.remove(partIndex); - } - return parts; - } - - public static Optional findNextLink(String line) { - int earliestLinkPosition = Integer.MAX_VALUE; - NextLink earliestNextLink = null; - for (LinkType possibleLinkType : LinkType.values()) { - Optional nextLink = possibleLinkType.findNext(line); - if (nextLink.isPresent()) { - if (nextLink.get().getPosition() < earliestLinkPosition) { - earliestNextLink = nextLink.get(); - earliestLinkPosition = earliestNextLink.getPosition(); - } - } - } - return Optional.fromNullable(earliestNextLink); - } - - private void renderSoneLink(List parts, String line) { - if (line.length() >= (7 + 43)) { - String soneId = line.substring(7, 50); - Optional sone = soneProvider.getSone(soneId); - parts.add(new SonePart(sone.or(new IdOnlySone(soneId)))); - } else { - parts.add(new PlainTextPart(line)); - } - } - - private void renderPostLink(List parts, String line) { - if (line.length() >= (7 + 36)) { - String postId = line.substring(7, 43); - Optional post = postProvider.getPost(postId); - if (post.isPresent()) { - parts.add(new PostPart(post.get())); - } else { - parts.add(new PlainTextPart(line.substring(0, 43))); - } - } else { - parts.add(new PlainTextPart(line)); - } - } - - private void renderFreenetLink(List parts, String link, LinkType linkType, @Nullable SoneTextParserContext context) { - String name = link; - String linkWithoutParameters = link; - if (name.indexOf('?') > -1) { - linkWithoutParameters = name = name.substring(0, name.indexOf('?')); - } - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - try { - FreenetURI uri = new FreenetURI(name); - name = uri.lastMetaString(); - if (name == null) { - name = uri.getDocName(); - } - if (name == null) { - name = link.substring(0, Math.min(9, link.length())); - } - boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (context != null) && (context.getPostingSone() != null) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId()); - parts.add(new FreenetLinkPart(link, name, linkWithoutParameters, fromPostingSone)); - } catch (MalformedURLException mue1) { - /* not a valid link, insert as plain text. */ - parts.add(new PlainTextPart(link)); - } catch (NullPointerException npe1) { - /* FreenetURI sometimes throws these, too. */ - parts.add(new PlainTextPart(link)); - } catch (ArrayIndexOutOfBoundsException aioobe1) { - /* oh, and these, too. */ - parts.add(new PlainTextPart(link)); - } - } - - private void renderHttpLink(List parts, String link, LinkType linkType) { - String name = link.substring(linkType == LinkType.HTTP ? 7 : 8); - int firstSlash = name.indexOf('/'); - int lastSlash = name.lastIndexOf('/'); - if ((lastSlash - firstSlash) > 3) { - name = name.substring(0, firstSlash + 1) + "…" + name.substring(lastSlash); - } - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - if (((name.indexOf('/') > -1) && (name.indexOf('.') < name.lastIndexOf('.', name.indexOf('/'))) || ((name.indexOf('/') == -1) && (name.indexOf('.') < name.lastIndexOf('.')))) && name.startsWith("www.")) { - name = name.substring(4); - } - if (name.indexOf('?') > -1) { - name = name.substring(0, name.indexOf('?')); - } - parts.add(new LinkPart(link, name)); - } - - private void renderFreemailLink(List parts, String line) { - int separator = line.indexOf('@'); - String freemailId = line.substring(separator + 1, separator + 53); - String identityId = Base64.encode(Base32.decode(freemailId)); - String emailLocalPart = line.substring(0, separator); - parts.add(new FreemailPart(emailLocalPart, freemailId, identityId)); - } - - private static boolean isPunctuation(char character) { - return (character == '.') || (character == ',') || (character == '!') || (character == '?'); - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/BookmarkDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/BookmarkDatabase.kt new file mode 100644 index 0000000..f44c1b8 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/BookmarkDatabase.kt @@ -0,0 +1,16 @@ +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Post + +/** + * Database interface for bookmark-related functionality. + */ +interface BookmarkDatabase { + + val bookmarkedPosts: Set + + fun bookmarkPost(post: Post) + fun unbookmarkPost(post: Post) + fun isPostBookmarked(post: Post): Boolean + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/Database.kt b/src/main/kotlin/net/pterodactylus/sone/database/Database.kt new file mode 100644 index 0000000..522ce32 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/Database.kt @@ -0,0 +1,31 @@ +/* + * Sone - Database.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 com.google.common.util.concurrent.Service + +/** + * Database for Sone data. This interface combines the various provider, + * store, and builder factory interfaces into a single interface. + */ +interface Database : Service, SoneDatabase, FriendDatabase, PostDatabase, PostReplyDatabase, AlbumDatabase, ImageDatabase, BookmarkDatabase { + + @Throws(DatabaseException::class) + fun save() + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/FriendDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/FriendDatabase.kt new file mode 100644 index 0000000..75e5623 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/FriendDatabase.kt @@ -0,0 +1,6 @@ +package net.pterodactylus.sone.database + +/** + * Combines a [FriendProvider] and a [FriendStore] into a friend database. + */ +interface FriendDatabase : FriendProvider, FriendStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt new file mode 100644 index 0000000..f56f2f7 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/FriendProvider.kt @@ -0,0 +1,13 @@ +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Sone + +/** + * Provides information about [friends][Sone.getFriends] of a [Sone]. + */ +interface FriendProvider { + + fun getFriends(localSone: Sone): Collection + fun isFriend(localSone: Sone, friendSoneId: String): Boolean + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/FriendStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/FriendStore.kt new file mode 100644 index 0000000..5e7a222 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/FriendStore.kt @@ -0,0 +1,13 @@ +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Sone + +/** + * Stores information about the [friends][Sone.getFriends] of a [Sone]. + */ +interface FriendStore { + + fun addFriend(localSone: Sone, friendSoneId: String) + fun removeFriend(localSone: Sone, friendSoneId: String) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt new file mode 100644 index 0000000..5ceb28e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilder.kt @@ -0,0 +1,31 @@ +/* + * Sone - ImageBuilder.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.Image + +/** + * Builder for [Image] objects. + */ +interface ImageBuilder { + + fun randomId(): ImageBuilder + fun withId(id: String): ImageBuilder + + fun build(): Image + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt new file mode 100644 index 0000000..bae797c --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageBuilderFactory.kt @@ -0,0 +1,27 @@ +/* + * Sone - ImageBuilderFactory.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 [ImageBuilder]s. + */ +interface ImageBuilderFactory { + + fun newImageBuilder(): ImageBuilder + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt new file mode 100644 index 0000000..4617cef --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageDatabase.kt @@ -0,0 +1,24 @@ +/* + * Sone - ImageDatabase.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 [ImageProvider], an [ImageBuilderFactory], and an + * [ImageStore] into an image database. + */ +interface ImageDatabase : ImageProvider, ImageBuilderFactory, ImageStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt new file mode 100644 index 0000000..c7cc75e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageProvider.kt @@ -0,0 +1,31 @@ +/* + * Sone - ImageProvider.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.Image + +import com.google.common.base.Optional + +/** + * Provides [Image]s. + */ +interface ImageProvider { + + fun getImage(imageId: String): Image? + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt new file mode 100644 index 0000000..91cff2d --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ImageStore.kt @@ -0,0 +1,30 @@ +/* + * Sone - ImageStore.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.Image + +/** + * Manages [Image] storage. + */ +interface ImageStore { + + fun storeImage(image: Image) + fun removeImage(image: Image) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt new file mode 100644 index 0000000..c1377ca --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilder.kt @@ -0,0 +1,75 @@ +/* + * Sone - PostBuilder.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.Post +import net.pterodactylus.sone.data.Sone + +/** + * Builder for [Post] objects. + * + * + * A [Post] consists of the following elements: + * + * * an ID, + * * a [sender][Sone], + * * an optional [recipient][Sone], + * * a time, + * * and a text. + * + * Except for the recipient, all this elements have to be configured on this + * builder. For the ID you have the possibility to configure either a random ID + * (which should be used for new posts) or a custom ID you specify (for creating + * an existing post). For the time you can use the current time (again, for + * creating new posts) or the given time (for loading posts). It is an error to + * specify both ways for either the ID or the time. + */ +interface PostBuilder { + + fun copyPost(post: Post): PostBuilder + + fun from(senderId: String): PostBuilder + + fun randomId(): PostBuilder + fun withId(id: String): PostBuilder + + fun currentTime(): PostBuilder + fun withTime(time: Long): PostBuilder + + fun withText(text: String): PostBuilder + + fun to(recipientId: String): PostBuilder + + /** + * Verifies this builder’s configuration and creates a new post. + * + * The following conditions must be met in order for this builder to be + * configured correctly: + * + * * Exactly one of [randomId] or [withId] must have been called. + * * The [sender][from] must not be `null`. + * * Exactly one of [currentTime] or [withTime] must have been called. + * * The [text][withText] must not be `null` and must contain something other than whitespace. + * * The [recipient][to] must either not have been set, or it must have been set to a [Sone] other than [the sender][from]. + * + * @return A new post + * @throws IllegalStateException if this builder’s configuration is not valid + */ + fun build(): Post + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt new file mode 100644 index 0000000..d7604c3 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostBuilderFactory.kt @@ -0,0 +1,32 @@ +/* + * Sone - PostBuilderFactory.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.database.memory.MemoryDatabase + +import com.google.inject.ImplementedBy + +/** + * Factory for [PostBuilder]s. + */ +@ImplementedBy(MemoryDatabase::class) +interface PostBuilderFactory { + + fun newPostBuilder(): PostBuilder + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt new file mode 100644 index 0000000..7b97c6a --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostDatabase.kt @@ -0,0 +1,24 @@ +/* + * Sone - PostDatabase.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 a [PostProvider], a [PostBuilderFactory], and a + * [PostStore] into a complete post database. + */ +interface PostDatabase : PostProvider, PostBuilderFactory, PostStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt new file mode 100644 index 0000000..37cb2a1 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostProvider.kt @@ -0,0 +1,36 @@ +/* + * Sone - PostProvider.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.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 + +/** + * Interface for objects that can provide [Post]s by their ID. + */ +@ImplementedBy(MemoryDatabase::class) +interface PostProvider { + + fun getPost(postId: String): Post? + fun getPosts(soneId: String): Collection + fun getDirectedPosts(recipientId: String): Collection + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt new file mode 100644 index 0000000..0c333da --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilder.kt @@ -0,0 +1,46 @@ +/* + * Sone - PostReplyBuilder.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.PostReply + +/** + * Builder for a [PostReply] object. + */ +interface PostReplyBuilder : ReplyBuilder { + + fun to(postId: String): PostReplyBuilder + + /** + * Verifies the configuration of this builder and creates a new post reply. + * + * The following conditions must be met in order for the configuration to be + * considered valid: + * + * * Exactly one of [randomId] or [withId] must have been called. + * * The [sender][from] must not be `null`. + * * Exactly one of [currentTime] or [withTime] must have been called. + * * The [text][withText] must not be `null` and must contain something other than whitespace. + * * The [post][to] must have been set. + * + * @return The created post reply + * @throws IllegalStateException if this builder’s configuration is not valid + */ + fun build(): PostReply + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt new file mode 100644 index 0000000..d039cda --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyBuilderFactory.kt @@ -0,0 +1,32 @@ +/* + * Sone - PostReplyBuilderFactory.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.database.memory.MemoryDatabase + +import com.google.inject.ImplementedBy + +/** + * Factory for [PostReplyBuilder]s. + */ +@ImplementedBy(MemoryDatabase::class) +interface PostReplyBuilderFactory { + + fun newPostReplyBuilder(): PostReplyBuilder + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt new file mode 100644 index 0000000..8f08cf3 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyDatabase.kt @@ -0,0 +1,24 @@ +/* + * Sone - PostReplyDatabase.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 a [PostReplyProvider], a [PostReplyBuilderFactory], and + * a [PostReplyStore] into a complete post reply database. + */ +interface PostReplyDatabase : PostReplyProvider, PostReplyBuilderFactory, PostReplyStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt new file mode 100644 index 0000000..7e09017 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyProvider.kt @@ -0,0 +1,38 @@ +/* + * Sone - PostReplyProvider.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 com.google.common.base.Optional +import net.pterodactylus.sone.data.PostReply + +/** + * Interface for objects that can provide [PostReply]s. + */ +interface PostReplyProvider { + + fun getPostReply(id: String): PostReply? + + /** + * Returns all replies for the given post, order ascending by time. + * + * @param postId The ID of the post to get all replies for + * @return All replies for the given post + */ + fun getReplies(postId: String): List + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt new file mode 100644 index 0000000..08ba380 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostReplyStore.kt @@ -0,0 +1,31 @@ +/* + * Sone - PostReplyStore.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.PostReply +import net.pterodactylus.sone.data.Sone + +/** + * Defines a store for [post replies][PostReply]. + */ +interface PostReplyStore { + + fun storePostReply(postReply: PostReply) + fun removePostReply(postReply: PostReply) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt new file mode 100644 index 0000000..3cb5f17 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/PostStore.kt @@ -0,0 +1,31 @@ +/* + * Sone - PostStore.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.Post +import net.pterodactylus.sone.data.Sone + +/** + * Interface for a store for posts. + */ +interface PostStore { + + fun storePost(post: Post) + fun removePost(post: Post) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt new file mode 100644 index 0000000..1aa6039 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/ReplyBuilder.kt @@ -0,0 +1,39 @@ +/* + * Sone - ReplyBuilder.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.Reply +import net.pterodactylus.sone.data.Sone + +/** + * Methods that all reply builders need to implement in order to be able to + * create any kind of [Reply]. + * + * @param B The type of the builder + */ +interface ReplyBuilder> { + + fun randomId(): B + fun withId(id: String): B + + fun from(senderId: String): B + fun currentTime(): B + fun withTime(time: Long): B + fun withText(text: String): B + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilder.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilder.kt new file mode 100644 index 0000000..35c444c --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilder.kt @@ -0,0 +1,16 @@ +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.freenet.wot.Identity + +/** + * Builder for [Sone] objects. + */ +interface SoneBuilder { + + fun from(identity: Identity): SoneBuilder + fun local(): SoneBuilder + + fun build(): Sone + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilderFactory.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilderFactory.kt new file mode 100644 index 0000000..c1dee54 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneBuilderFactory.kt @@ -0,0 +1,10 @@ +package net.pterodactylus.sone.database + +/** + * Factory for [SoneBuilder]s. + */ +interface SoneBuilderFactory { + + fun newSoneBuilder(): SoneBuilder + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneDatabase.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneDatabase.kt new file mode 100644 index 0000000..3533f69 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneDatabase.kt @@ -0,0 +1,7 @@ +package net.pterodactylus.sone.database + +/** + * Combines a [SoneProvider] and a [SoneStore] into a Sone + * database. + */ +interface SoneDatabase : SoneProvider, SoneBuilderFactory, SoneStore diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt new file mode 100644 index 0000000..b8ce5e1 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneProvider.kt @@ -0,0 +1,40 @@ +/* + * Sone - SoneProvider.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.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 + +/** + * Interface for objects that can provide [Sone]s by their ID. + */ +@ImplementedBy(Core::class) +interface SoneProvider { + + val sones: Collection + val localSones: Collection + val remoteSones: Collection + val soneLoader: (String) -> Sone? + + fun getSone(soneId: String): Sone? + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/database/SoneStore.kt b/src/main/kotlin/net/pterodactylus/sone/database/SoneStore.kt new file mode 100644 index 0000000..20cc3f4 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/database/SoneStore.kt @@ -0,0 +1,13 @@ +package net.pterodactylus.sone.database + +import net.pterodactylus.sone.data.Sone + +/** + * Interface for a store for [Sone]s. + */ +interface SoneStore { + + fun storeSone(sone: Sone) + fun removeSone(sone: Sone) + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/template/ParserFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/ParserFilter.kt index cec5d56..67b03f3 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/ParserFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/ParserFilter.kt @@ -20,7 +20,7 @@ class ParserFilter @Inject constructor(private val core: Core, private val soneT val text = data?.toString() ?: return listOf() val soneParameter = parameters?.get("sone") val sone = when (soneParameter) { - is String -> core.getSone(soneParameter).orNull() + is String -> core.getSone(soneParameter) is Sone -> soneParameter else -> null } diff --git a/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt index 43331c3..25df239 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt @@ -101,7 +101,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 soneName = sone.transform(SoneAccessor::getNiceName).or(freemailPart.identityId) + val soneName = sone?.let(SoneAccessor::getNiceName) ?: freemailPart.identityId renderLink(writer, "/Freemail/NewMessage?to=${freemailPart.identityId}", "${freemailPart.emailLocalPart}@$soneName.freemail", diff --git a/src/main/kotlin/net/pterodactylus/sone/text/FreenetLinkPart.kt b/src/main/kotlin/net/pterodactylus/sone/text/FreenetLinkPart.kt index 3744fd7..43b9f4a 100644 --- a/src/main/kotlin/net/pterodactylus/sone/text/FreenetLinkPart.kt +++ b/src/main/kotlin/net/pterodactylus/sone/text/FreenetLinkPart.kt @@ -5,7 +5,7 @@ package net.pterodactylus.sone.text * link is an SSK or USK link and the post was created by an identity that owns * the keyspace in question. */ -data class FreenetLinkPart(val link: String, override val text: String, val title: String, val trusted: Boolean) : Part { +data class FreenetLinkPart(val link: String, override val text: String, val title: String, val trusted: Boolean = false) : Part { constructor(link: String, text: String, trusted: Boolean) : this(link, text, link, trusted) diff --git a/src/main/kotlin/net/pterodactylus/sone/text/LinkPart.kt b/src/main/kotlin/net/pterodactylus/sone/text/LinkPart.kt index 7099b93..3563b37 100644 --- a/src/main/kotlin/net/pterodactylus/sone/text/LinkPart.kt +++ b/src/main/kotlin/net/pterodactylus/sone/text/LinkPart.kt @@ -5,8 +5,4 @@ package net.pterodactylus.sone.text * attributes: the link itself, the text that is shown instead of the link, and * an explanatory text that can be displayed e.g. as a tooltip. */ -data class LinkPart(val link: String, override val text: String, val title: String) : Part { - - constructor(link: String, text: String) : this(link, text, link) - -} +data class LinkPart @JvmOverloads constructor(val link: String, override val text: String, val title: String = link) : Part diff --git a/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt b/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt new file mode 100644 index 0000000..64125c1 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/text/SoneTextParser.kt @@ -0,0 +1,197 @@ +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 net.pterodactylus.sone.text.LinkType.USK +import net.pterodactylus.sone.utils.let +import org.bitpedia.util.Base32 +import java.net.MalformedURLException + +/** + * [Parser] implementation that can recognize Freenet URIs. + */ +class SoneTextParser(private val soneProvider: SoneProvider?, private val postProvider: PostProvider?) { + + fun parse(source: String, context: SoneTextParserContext?) = + source.split("\n") + .dropWhile { it.trim() == "" } + .dropLastWhile { it.trim() == "" } + .mergeMultipleEmptyLines() + .flatMap { splitLineIntoParts(it, context) } + .removeEmptyPlainTextParts() + .mergeAdjacentPlainTextParts() + + private fun splitLineIntoParts(line: String, context: SoneTextParserContext?) = + generateSequence(PlainTextPart("") as Part to line) { remainder -> + if (remainder.second == "") + null + else + LinkType.values() + .mapNotNull { it.findNext(remainder.second) } + .minBy { it.position } + .let { + when { + it == null -> PlainTextPart(remainder.second) to "" + it.position == 0 -> it.toPart(context) to it.remainder + else -> PlainTextPart(remainder.second.substring(0, it.position)) to (it.link + it.remainder) + } + } + }.map { it.first }.toList() + + private fun NextLink.toPart(context: SoneTextParserContext?) = when (linkType) { + KSK, CHK -> try { + FreenetURI(link).let { freenetUri -> + FreenetLinkPart( + link, + if (freenetUri.isKSK) { + freenetUri.guessableKey + } else { + freenetUri.metaString ?: freenetUri.docName ?: link.substring(0, 9) + }, + link.split('?').first() + ) + } + } catch (e: MalformedURLException) { + PlainTextPart(link) + } + SSK, USK -> + try { + FreenetLinkPart(link, FreenetURI(link).docName, trusted = context?.routingKey?.contentEquals(FreenetURI(link).routingKey) == true) + } catch (e: MalformedURLException) { + PlainTextPart(link) + } + SONE -> link.substring(7).let { SonePart(soneProvider?.getSone(it) ?: IdOnlySone(it)) } + POST -> postProvider?.getPost(link.substring(7))?.let { PostPart(it) } ?: PlainTextPart(link) + FREEMAIL -> link.indexOf('@').let { atSign -> + link.substring(atSign + 1, link.length - 9).let { freemailId -> + FreemailPart(link.substring(0, atSign), freemailId, freemailId.decodedId) + } + } + HTTP, HTTPS -> LinkPart(link, link + .withoutProtocol + .withoutWwwPrefix + .withoutUrlParameters + .withoutMiddlePathComponents + .withoutTrailingSlash) + } + +} + +private fun List.mergeMultipleEmptyLines() = fold(emptyList()) { previous, current -> + if (previous.isEmpty()) { + previous + current + } else { + if ((previous.last() == "\n") && (current == "")) { + previous + } else { + previous + ("\n" + current) + } + } +} + +private fun List.mergeAdjacentPlainTextParts() = fold(emptyList()) { parts, part -> + if ((parts.lastOrNull() is PlainTextPart) && (part is PlainTextPart)) { + parts.dropLast(1) + PlainTextPart(parts.last().text + part.text) + } else { + parts + part + } +} + +private fun List.removeEmptyPlainTextParts() = filterNot { it == PlainTextPart("") } + +private val String.decodedId: String get() = Base64.encode(Base32.decode(this)) +private val String.withoutProtocol get() = substring(indexOf("//") + 2) +private val String.withoutUrlParameters get() = split('?').first() + +private val String.withoutWwwPrefix + get() = split("/") + .replaceFirst { it.split(".").dropWhile { it == "www" }.joinToString(".") } + .joinToString("/") + +private fun List.replaceFirst(replacement: (T) -> T) = mapIndexed { index, element -> + if (index == 0) replacement(element) else element +} + +private val String.withoutMiddlePathComponents + get() = split("/").let { + if (it.size > 2) { + "${it.first()}/…/${it.last()}" + } else { + it.joinToString("/") + } + } +private val String.withoutTrailingSlash get() = if (endsWith("/")) substring(0, length - 1) else this +private val SoneTextParserContext.routingKey: ByteArray? get() = postingSone?.routingKey +private val Sone.routingKey: ByteArray get() = Base64.decode(id) + +private enum class LinkType(private val scheme: String, private val freenetLink: Boolean) { + + KSK("KSK@", true), + CHK("CHK@", true), + SSK("SSK@", true), + USK("USK@", true), + HTTP("http://", false), + HTTPS("https://", false), + SONE("sone://", false) { + override fun validateLinkLength(length: Int) = length.takeIf { it == 50 } + }, + POST("post://", false), + FREEMAIL("", true) { + override fun findNext(line: String): NextLink? { + val nextFreemailSuffix = line.indexOf(".freemail").takeIf { it >= 54 } ?: return null + if (line[nextFreemailSuffix - 53] != '@') return null + if (!line.substring(nextFreemailSuffix - 52, nextFreemailSuffix).matches(Regex("^[a-z2-7]*\$"))) return null + val firstCharacterIndex = generateSequence(nextFreemailSuffix - 53) { + it.minus(1).takeIf { (it >= 0) && line[it].validLocalPart } + }.lastOrNull() ?: return null + return NextLink(firstCharacterIndex, this, line.substring(firstCharacterIndex, nextFreemailSuffix + 9), line.substring(nextFreemailSuffix + 9)) + } + + private val Char.validLocalPart get() = (this in ('A'..'Z')) || (this in ('a'..'z')) || (this in ('0'..'9')) || (this == '-') || (this == '_') || (this == '.') + }; + + open fun findNext(line: String): NextLink? { + val nextLinkPosition = line.indexOf(scheme).takeIf { it != -1 } ?: return null + val endOfLink = line.substring(nextLinkPosition).findEndOfLink().validate() ?: return null + val link = line.substring(nextLinkPosition, nextLinkPosition + endOfLink) + val realNextLinkPosition = if (freenetLink && line.substring(0, nextLinkPosition).endsWith("freenet:")) nextLinkPosition - 8 else nextLinkPosition + return NextLink(realNextLinkPosition, this, link, line.substring(nextLinkPosition + endOfLink)) + } + + private fun String.findEndOfLink() = + substring(0, whitespace.find(this)?.range?.start ?: length) + .dropLastWhile(::isPunctuation) + .upToFirstUnmatchedParen() + + private fun Int.validate() = validateLinkLength(this) + protected open fun validateLinkLength(length: Int) = length.takeIf { it > scheme.length } + + private fun String.upToFirstUnmatchedParen() = + foldIndexed(Pair(0, null)) { index, (openParens, firstUnmatchedParen), currentChar -> + when (currentChar) { + '(' -> (openParens + 1) to firstUnmatchedParen + ')' -> ((openParens - 1) to (if (openParens == 0) (firstUnmatchedParen ?: index) else firstUnmatchedParen)) + else -> openParens to firstUnmatchedParen + } + }.second ?: length + +} + +private val punctuationChars = listOf('.', ',', '?', '!') +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) diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt new file mode 100644 index 0000000..bd67ae2 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/utils/Memoize.kt @@ -0,0 +1,12 @@ +package net.pterodactylus.sone.utils + +class Memoize(private val calc: (T) -> R) : (T) -> R { + + private val values = mutableMapOf() + + override fun invoke(value: T) = + values.getOrPut(value, { calc(value) }) + +} + +fun ((T) -> R).memoize(): (T) -> R = Memoize(this) 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 b185d2b..35ac0e2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.kt @@ -1,6 +1,5 @@ package net.pterodactylus.sone.web.ajax -import net.pterodactylus.sone.utils.also import net.pterodactylus.sone.utils.emptyToNull import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface @@ -15,9 +14,10 @@ class BookmarkAjaxPage(webInterface: WebInterface) : JsonPage("bookmark.ajax", w override fun createJsonObject(request: FreenetRequest) = request.parameters["post"].emptyToNull - ?.let(core::getPost) - ?.also(core::bookmarkPost) - ?.let { createSuccessJsonObject() } + ?.let { postId -> + core.getPost(postId)?.also(core::bookmarkPost) + createSuccessJsonObject() + } ?: createErrorJsonObject("invalid-post-id") } 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 ec65b55..868e990 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.kt @@ -2,6 +2,7 @@ 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 @@ -18,13 +19,13 @@ class CreatePostAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("createP request.parameters["text"].emptyToNull ?.let { TextFilter.filter(request.headers["Host"], it) } ?.let { text -> - val sender = request.parameters["sender"].emptyToNull?.let(core::getSone)?.orNull() ?: currentSone - val recipient = request.parameters["recipient"].let(core::getSone) - core.createPost(sender, recipient, text).let { post -> + val sender = request.parameters["sender"].emptyToNull?.let(core::getSone) ?: currentSone + val recipient = request.parameters["recipient"]?.let(core::getSone) + core.createPost(sender, recipient.asOptional(), text).let { post -> createSuccessJsonObject().apply { put("postId", post.id) put("sone", sender.id) - put("recipient", recipient.let(Sone::getId)) + put("recipient", recipient?.id) } } } ?: createErrorJsonObject("text-required") 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 76d867e..6dcf032 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.kt @@ -14,7 +14,7 @@ class DeletePostAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("deleteP override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["post"] - .let(core::getPost) + ?.let(core::getPost) ?.let { post -> post.sone.isLocal.ifTrue { createSuccessJsonObject().also { 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 2108daf..d01c077 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.kt @@ -14,7 +14,7 @@ class DeleteReplyAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("delete override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["reply"] - .let(core::getPostReply) + ?.let(core::getPostReply) ?.let { reply -> reply.sone.isLocal.ifTrue { createSuccessJsonObject().also { 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 e4f8435..4eadfde 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.kt @@ -16,7 +16,7 @@ class DistrustAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("distrustS override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] - .let(core::getSone) + ?.let(core::getSone) ?.let { sone -> createSuccessJsonObject() .put("trustValue", core.preferences.negativeTrust) 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 c6aa25e..0c37ac0 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.kt @@ -14,7 +14,7 @@ class FollowSoneAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("followS override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] - .let(core::getSone) + ?.let(core::getSone) ?.also { core.followSone(currentSone, it.id) } ?.also(core::markSoneKnown) ?.let { createSuccessJsonObject() } 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 335f269..77e2c87 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.kt @@ -20,12 +20,12 @@ class GetLikesAjaxPage(webInterface: WebInterface) : JsonPage("getLikes.ajax", w override fun createJsonObject(request: FreenetRequest) = when (request.parameters["type"]) { "post" -> request.parameters["post"] - .let(core::getPost) + ?.let(core::getPost) ?.let(core::getLikes) ?.toReply() ?: createErrorJsonObject("invalid-post-id") "reply" -> request.parameters["reply"] - .let(core::getPostReply) + ?.let(core::getPostReply) ?.let(core::getLikes) ?.toReply() ?: createErrorJsonObject("invalid-reply-id") 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 2d902a6..d91fe90 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.kt @@ -19,8 +19,8 @@ class GetPostAjaxPage(webInterface: WebInterface, private val postTemplate: Temp override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["post"] - .let(core::getPost) - .let { post -> + ?.let(core::getPost) + ?.let { post -> createSuccessJsonObject(). put("post", jsonObject( "id" to post.id, 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 fc4b482..b02b85b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.kt @@ -19,7 +19,7 @@ class GetReplyAjaxPage(webInterface: WebInterface, private val template: Templat override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["reply"] - .let(core::getPostReply) + ?.let(core::getPostReply) ?.let { it.toJson(currentSone, request) } ?.let { replyJson -> createSuccessJsonObject().apply { 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 acb8cec..7646704 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt @@ -36,7 +36,7 @@ class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: E this["loggedIn"] = currentSone != null this["options"] = currentSone?.options?.toJsonOptions() ?: jsonObject {} this["notificationHash"] = webInterface.getNotifications(currentSone).sortedBy { it.createdTime }.hashCode() - this["sones"] = request.httpRequest.getParam("soneIds").split(',').mapPresent(core::getSone).plus(currentSone).filterNotNull().toJsonSones() + this["sones"] = request.httpRequest.getParam("soneIds").split(',').mapNotNull(core::getSone).plus(currentSone).filterNotNull().toJsonSones() this["newPosts"] = webInterface.getNewPosts(currentSone).toJsonPosts() this["newReplies"] = webInterface.getNewReplies(currentSone).toJsonReplies() this["linkedElements"] = request.httpRequest.getParam("elements", "[]").asJson().map(JsonNode::asText).map(elementLoader::loadElement).toJsonElements() 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 fb2592e..cb3b86d 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.kt @@ -3,7 +3,6 @@ package net.pterodactylus.sone.web.ajax import net.pterodactylus.sone.freenet.L10nFilter import net.pterodactylus.sone.text.TimeTextConverter 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 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 4257725..718e6e7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/LikeAjaxPage.kt @@ -14,13 +14,13 @@ class LikeAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("like.ajax", w override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = when (request.parameters["type"]) { "post" -> request.parameters["post"] - .let(core::getPost) + ?.let(core::getPost) ?.let { currentSone.addLikedPostId(it.id) } ?.also { core.touchConfiguration() } ?.let { createSuccessJsonObject() } ?: createErrorJsonObject("invalid-post-id") "reply" -> request.parameters["reply"] - .let(core::getPostReply) + ?.let(core::getPostReply) ?.let { currentSone.addLikedReplyId(it.id) } ?.also { core.touchConfiguration() } ?.let { createSuccessJsonObject() } 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 9e4e4a3..0451eaa 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.kt @@ -1,7 +1,5 @@ package net.pterodactylus.sone.web.ajax -import com.google.common.base.Optional -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 @@ -21,10 +19,10 @@ class MarkAsKnownAjaxPage(webInterface: WebInterface) : JsonPage("markAsKnown.aj else -> createErrorJsonObject("invalid-type") } - private fun processIds(request: FreenetRequest, getter: (String) -> Optional, marker: (T) -> Unit) = + private fun processIds(request: FreenetRequest, getter: (String) -> T?, marker: (T) -> Unit) = request.parameters["id"] ?.split(Regex(" +")) - ?.mapPresent(getter) + ?.mapNotNull(getter) ?.onEach(marker) .let { createSuccessJsonObject() } 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 9a01af8..1dfb058 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/TrustAjaxPage.kt @@ -15,7 +15,7 @@ class TrustAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("trustSone.aj override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] - .let(core::getSone) + ?.let(core::getSone) ?.let { core.trustSone(currentSone, it) } ?.let { createSuccessJsonObject().put("trustValue", core.preferences.positiveTrust) } ?: createErrorJsonObject("invalid-sone-id") 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 6889d04..83b474c 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.kt @@ -12,8 +12,8 @@ class UnfollowSoneAjaxPage(webInterface: WebInterface) : LoggedInJsonPage("unfol override fun createJsonObject(currentSone: Sone, request: FreenetRequest) = request.parameters["sone"] - ?.takeIf { core.getSone(it).isPresent } - ?.also { core.unfollowSone(currentSone, it) } + ?.let(core::getSone) + ?.also { core.unfollowSone(currentSone, it.id) } ?.let { createSuccessJsonObject() } ?: createErrorJsonObject("invalid-sone-id") 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 519d49e..7fb2320 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/BookmarkPage.kt @@ -16,7 +16,7 @@ class BookmarkPage(template: Template, webInterface: WebInterface) if (freenetRequest.isPOST) { val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) val postId = freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36) - webInterface.core.getPost(postId).orNull()?.let { + webInterface.core.getPost(postId)?.let { webInterface.core.bookmarkPost(it) } throw RedirectException(returnPage) 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 ee3936e..b0eea08 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateAlbumPage.kt @@ -1,6 +1,7 @@ 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 @@ -12,9 +13,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user create a new album. */ class CreateAlbumPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("createAlbum.html", template, "Page.CreateAlbum.Title", webInterface, true) { + LoggedInPage("createAlbum.html", template, "Page.CreateAlbum.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { val name = freenetRequest.httpRequest.getPartAsStringFailsafe("name", 64).trim() if (name.isEmpty()) { @@ -22,7 +23,6 @@ class CreateAlbumPage(template: Template, webInterface: WebInterface): return } val description = freenetRequest.httpRequest.getPartAsStringFailsafe("description", 256).trim() - val currentSone = webInterface.getCurrentSoneCreatingSession(freenetRequest.toadletContext) 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) 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 30a1c31..31896f7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreatePostPage.kt @@ -1,6 +1,8 @@ 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 @@ -11,9 +13,9 @@ import net.pterodactylus.util.template.TemplateContext * This page lets the user create a new [Post]. */ class CreatePostPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("createPost.html", template, "Page.CreatePost.Title", webInterface, true) { + LoggedInPage("createPost.html", template, "Page.CreatePost.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) templateContext["returnPage"] = returnPage if (freenetRequest.isPOST) { @@ -22,9 +24,9 @@ class CreatePostPage(template: Template, webInterface: WebInterface): templateContext["errorTextEmpty"] = true return } - val sender = webInterface.core.getLocalSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: getCurrentSone(freenetRequest.toadletContext) + 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, TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), text)) + webInterface.core.createPost(sender, recipient.asOptional(), TextFilter.filter(freenetRequest.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 a6c58e4..bc6faa4 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/CreateReplyPage.kt @@ -1,5 +1,6 @@ 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 @@ -11,9 +12,9 @@ import net.pterodactylus.util.template.TemplateContext * This page lets the user post a reply to a post. */ class CreateReplyPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("createReply.html", template, "Page.CreateReply.Title", webInterface, true) { + LoggedInPage("createReply.html", template, "Page.CreateReply.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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 } @@ -22,8 +23,8 @@ class CreateReplyPage(template: Template, webInterface: WebInterface): templateContext["errorTextEmpty"] = true return } - val post = webInterface.core.getPost(postId).orNull() ?: throw RedirectException("noPermission.html") - val sender = webInterface.core.getLocalSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sender", 43)) ?: getCurrentSone(freenetRequest.toadletContext) + 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)) throw RedirectException(returnPage) } 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 98eea86..eff79b9 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteAlbumPage.kt @@ -1,5 +1,6 @@ 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 @@ -10,9 +11,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user delete an {@link Album}. */ class DeleteAlbumPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deleteAlbum.html", template, "Page.DeleteAlbum.Title", webInterface, true) { + LoggedInPage("deleteAlbum.html", template, "Page.DeleteAlbum.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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") if (!album.sone.isLocal) { 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 61db304..fb77707 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteImagePage.kt @@ -1,5 +1,6 @@ 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 @@ -10,9 +11,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user delete an {@link Image}. */ class DeleteImagePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deleteImage.html", template, "Page.DeleteImage.Title", webInterface, true) { + LoggedInPage("deleteImage.html", template, "Page.DeleteImage.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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") if (!image.sone.isLocal) { 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 21465d7..8eccfb4 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeletePostPage.kt @@ -1,5 +1,6 @@ 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 @@ -10,11 +11,11 @@ import net.pterodactylus.util.template.TemplateContext * Lets the user delete a post they made. */ class DeletePostPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deletePost.html", template, "Page.DeletePost.Title", webInterface, true) { + LoggedInPage("deletePost.html", template, "Page.DeletePost.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - val post = webInterface.core.getPost(freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36)).orNull() ?: throw RedirectException("noPermission.html") + val post = webInterface.core.getPost(freenetRequest.httpRequest.getPartAsStringFailsafe("post", 36)) ?: throw RedirectException("noPermission.html") val returnPage = freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256) if (!post.sone.isLocal) { throw RedirectException("noPermission.html") @@ -29,7 +30,7 @@ class DeletePostPage(template: Template, webInterface: WebInterface): templateContext["returnPage"] = returnPage return } - templateContext["post"] = webInterface.core.getPost(freenetRequest.httpRequest.getParam("post")).orNull() ?: throw RedirectException("noPermission.html") + templateContext["post"] = webInterface.core.getPost(freenetRequest.httpRequest.getParam("post")) ?: throw RedirectException("noPermission.html") templateContext["returnPage"] = freenetRequest.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 cf5ac6e..f25299f 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteProfileFieldPage.kt @@ -1,5 +1,6 @@ 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 @@ -10,10 +11,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user confirm the deletion of a profile field. */ class DeleteProfileFieldPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deleteProfileField.html", template, "Page.DeleteProfileField.Title", webInterface, true) { + LoggedInPage("deleteProfileField.html", template, "Page.DeleteProfileField.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - val currentSone = getCurrentSone(freenetRequest.toadletContext)!! + 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") { 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 c67d620..29d8c81 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteReplyPage.kt @@ -1,5 +1,6 @@ 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 @@ -10,12 +11,12 @@ import net.pterodactylus.util.template.TemplateContext * This page lets the user delete a reply. */ class DeleteReplyPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deleteReply.html", template, "Page.DeleteReply.Title", webInterface, true) { + LoggedInPage("deleteReply.html", template, "Page.DeleteReply.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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).orNull() ?: throw RedirectException("noPermission.html") + val reply = webInterface.core.getPostReply(replyId) ?: throw RedirectException("noPermission.html") if (!reply.sone.isLocal) { throw RedirectException("noPermission.html") } 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 0cce5ba..b2a6d7b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DeleteSonePage.kt @@ -1,5 +1,6 @@ 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 @@ -12,12 +13,12 @@ import net.pterodactylus.util.template.TemplateContext * installation. */ class DeleteSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("deleteSone.html", template, "Page.DeleteSone.Title", webInterface, true) { + LoggedInPage("deleteSone.html", template, "Page.DeleteSone.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { if (freenetRequest.httpRequest.isPartSet("deleteSone")) { - webInterface.core.deleteSone(getCurrentSone(freenetRequest.toadletContext)) + webInterface.core.deleteSone(currentSone) } throw RedirectException("index.html") } 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 ce5aaec..70755f5 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/DistrustPage.kt @@ -1,5 +1,6 @@ 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 @@ -13,12 +14,12 @@ import net.pterodactylus.util.template.TemplateContext * @see net.pterodactylus.sone.core.Core#distrustSone(Sone, Sone) */ class DistrustPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("distrust.html", template, "Page.Distrust.Title", webInterface, true) { + LoggedInPage("distrust.html", template, "Page.Distrust.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - val sone = webInterface.core.getSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sone", 44)).orNull() - sone?.run { webInterface.core.distrustSone(getCurrentSone(freenetRequest.toadletContext), this) } + webInterface.core.getSone(freenetRequest.httpRequest.getPartAsStringFailsafe("sone", 44)) + ?.run { webInterface.core.distrustSone(currentSone, this) } throw RedirectException(freenetRequest.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 bd612c3..26d7c3a 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditAlbumPage.kt @@ -1,6 +1,7 @@ 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 @@ -11,9 +12,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user edit the name and description of an album. */ class EditAlbumPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("editAlbum.html", template, "Page.EditAlbum.Title", webInterface, true) { + LoggedInPage("editAlbum.html", template, "Page.EditAlbum.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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") album.takeUnless { it.sone.isLocal }?.run { throw RedirectException("noPermission.html") } 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 b674cb9..350dec7 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditImagePage.kt @@ -1,6 +1,7 @@ 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 @@ -12,9 +13,9 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user edit title and description of an {@link Image}. */ class EditImagePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("editImage.html", template, "Page.EditImage.Title", webInterface, true) { + LoggedInPage("editImage.html", template, "Page.EditImage.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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") if (!image.sone.isLocal) { 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 5e3d3c6..f3486d2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfileFieldPage.kt @@ -1,5 +1,6 @@ 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 @@ -9,32 +10,30 @@ import net.pterodactylus.util.template.TemplateContext /** * Page that lets the user edit the name of a profile field. */ -class EditProfileFieldPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("editProfileField.html", template, "Page.EditProfileField.Title", webInterface, true) { +class EditProfileFieldPage(template: Template, webInterface: WebInterface) : + LoggedInPage("editProfileField.html", template, "Page.EditProfileField.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - sessionProvider.getCurrentSone(freenetRequest.toadletContext)!!.let { currentSone -> - currentSone.profile.let { profile -> - if (freenetRequest.isPOST) { - if (freenetRequest.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 -> - try { - if (name != field.name) { - field.name = name - currentSone.profile = profile - } - throw RedirectException("editProfile.html#profile-fields") - } catch (e: IllegalArgumentException) { - templateContext["duplicateFieldName"] = true - return + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { + currentSone.profile.let { profile -> + if (freenetRequest.isPOST) { + if (freenetRequest.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 -> + try { + if (name != field.name) { + field.name = name + currentSone.profile = profile } + throw RedirectException("editProfile.html#profile-fields") + } catch (e: IllegalArgumentException) { + templateContext["duplicateFieldName"] = true + return } } - templateContext["field"] = profile.getFieldById(freenetRequest.httpRequest.getParam("field")) ?: throw RedirectException("invalid.html") } + templateContext["field"] = profile.getFieldById(freenetRequest.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 5ed0c2f..95c40c8 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/EditProfilePage.kt @@ -1,6 +1,7 @@ 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 @@ -11,11 +12,11 @@ import net.pterodactylus.util.template.TemplateContext /** * This page lets the user edit her profile. */ -class EditProfilePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("editProfile.html", template, "Page.EditProfile.Title", webInterface, true) { +class EditProfilePage(template: Template, webInterface: WebInterface) : + LoggedInPage("editProfile.html", template, "Page.EditProfile.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - freenetRequest.currentSone!!.profile.let { profile -> + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { + currentSone.profile.let { profile -> templateContext["firstName"] = profile.firstName templateContext["middleName"] = profile.middleName templateContext["lastName"] = profile.lastName @@ -36,13 +37,14 @@ class EditProfilePage(template: Template, webInterface: WebInterface): profile.fields.forEach { field -> field.value = TextFilter.filter(freenetRequest.httpRequest.getHeader("Host"), freenetRequest.httpRequest.getPartAsStringFailsafe("field-${field.id}", 400).trim()) } + currentSone.profile = profile webInterface.core.touchConfiguration() throw RedirectException("editProfile.html") } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("add-field", 4) == "true") { val fieldName = freenetRequest.httpRequest.getPartAsStringFailsafe("field-name", 100) try { profile.addField(fieldName) - freenetRequest.currentSone!!.profile = profile + currentSone.profile = profile webInterface.core.touchConfiguration() throw RedirectException("editProfile.html#profile-fields") } catch (e: DuplicateField) { @@ -56,11 +58,11 @@ class EditProfilePage(template: Template, webInterface: WebInterface): throw RedirectException("editProfileField.html?field=${field.id}") } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("move-down-field-${field.id}", 4) == "true") { profile.moveFieldDown(field) - freenetRequest.currentSone!!.profile = profile + currentSone.profile = profile throw RedirectException("editProfile.html#profile-fields") } else if (freenetRequest.httpRequest.getPartAsStringFailsafe("move-up-field-${field.id}", 4) == "true") { profile.moveFieldUp(field) - freenetRequest.currentSone!!.profile = profile + currentSone.profile = profile throw RedirectException("editProfile.html#profile-fields") } } @@ -68,6 +70,4 @@ class EditProfilePage(template: Template, webInterface: WebInterface): } } - private val FreenetRequest.currentSone get() = sessionProvider.getCurrentSone(toadletContext) - } 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 781e07f..cf5bcee 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/FollowSonePage.kt @@ -1,5 +1,6 @@ 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 @@ -10,22 +11,19 @@ import net.pterodactylus.util.template.TemplateContext * This page lets the user follow another Sone. */ class FollowSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("followSone.html", template, "Page.FollowSone.Title", webInterface, true) { + LoggedInPage("followSone.html", template, "Page.FollowSone.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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) } - .filter { it.second.isPresent } - .map { it.first to it.second.get() } + .filterNot { it.second == null } .forEach { sone -> - webInterface.core.followSone(freenetRequest.currentSone, sone.first) + webInterface.core.followSone(currentSone, sone.first) webInterface.core.markSoneKnown(sone.second) } throw RedirectException(freenetRequest.httpRequest.getPartAsStringFailsafe("returnPage", 256)) } } - private val FreenetRequest.currentSone get() = sessionProvider.getCurrentSone(toadletContext) - } 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 3181355..e9911e6 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ImageBrowserPage.kt @@ -14,9 +14,9 @@ import java.net.URI * The image browser page is the entry page for the image management. */ class ImageBrowserPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("imageBrowser.html", template, "Page.ImageBrowser.Title", webInterface, true) { + LoggedInPage("imageBrowser.html", template, "Page.ImageBrowser.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if ("album" in freenetRequest.parameters) { templateContext["albumRequested"] = true templateContext["album"] = webInterface.core.getAlbum(freenetRequest.parameters["album"]!!) @@ -40,7 +40,7 @@ class ImageBrowserPage(template: Template, webInterface: WebInterface): } } else { templateContext["soneRequested"] = true - templateContext["sone"] = webInterface.core.getSone(freenetRequest.httpRequest.getParam("sone")).orNull() ?: getCurrentSone(freenetRequest.toadletContext) + templateContext["sone"] = webInterface.core.getSone(freenetRequest.httpRequest.getParam("sone")) ?: currentSone } } 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 bf6e0c4..0257cb1 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt @@ -1,5 +1,6 @@ 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 @@ -13,15 +14,12 @@ import net.pterodactylus.util.template.TemplateContext * of all friends of the current user. */ class IndexPage(template: Template, webInterface: WebInterface, private val postVisibilityFilter: PostVisibilityFilter): - SoneTemplatePage("index.html", template, "Page.Index.Title", webInterface, true) { + LoggedInPage("index.html", template, "Page.Index.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - getCurrentSone(freenetRequest.toadletContext)!!.let { currentSone -> + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { (currentSone.posts + currentSone.friends - .map { webInterface.core.getSone(it) } - .filter { it.isPresent } - .map { it.get() } + .mapNotNull(webInterface.core::getSone) .flatMap { it.posts } + webInterface.core.getDirectedPosts(currentSone.id) ).distinct() @@ -35,7 +33,6 @@ class IndexPage(template: Template, webInterface: WebInterface, private val post templateContext["posts"] = pagination.items } } - } } } 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 43753a3..ef622df 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LikePage.kt @@ -1,5 +1,6 @@ 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 @@ -10,20 +11,18 @@ import net.pterodactylus.util.template.TemplateContext /** * 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) - : SoneTemplatePage("like.html", template, "Page.Like.Title", webInterface, true) { +class LikePage(template: Template, webInterface: WebInterface) : + LoggedInPage("like.html", template, "Page.Like.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - getCurrentSone(freenetRequest.toadletContext)!!.let { currentSone -> - freenetRequest.parameters["type", 16]?.also { type -> - when(type) { - "post" -> currentSone.addLikedPostId(freenetRequest.parameters["post", 36]!!) - "reply" -> currentSone.addLikedReplyId(freenetRequest.parameters["reply", 36]!!) - } + freenetRequest.parameters["type", 16]?.also { type -> + when (type) { + "post" -> currentSone.addLikedPostId(freenetRequest.parameters["post", 36]!!) + "reply" -> currentSone.addLikedReplyId(freenetRequest.parameters["reply", 36]!!) } - throw RedirectException(freenetRequest.parameters["returnPage", 256]!!) } + throw RedirectException(freenetRequest.parameters["returnPage", 256]!!) } } diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt new file mode 100644 index 0000000..c88499e --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LoggedInPage.kt @@ -0,0 +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 + +/** + * 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) { + + final override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + handleRequest(freenetRequest, getCurrentSone(freenetRequest.toadletContext, false)!!, templateContext) + } + + protected abstract fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) + +} 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 3a2a023..7e608ff 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/LogoutPage.kt @@ -1,6 +1,7 @@ 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 @@ -10,9 +11,9 @@ import net.pterodactylus.util.template.TemplateContext * Logs a user out. */ class LogoutPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("logout.html", template, "Page.Logout.Title", webInterface, true) { + LoggedInPage("logout.html", template, "Page.Logout.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { setCurrentSone(freenetRequest.toadletContext, null) throw RedirectException("index.html") } 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 570e570..49c1075 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/MarkAsKnownPage.kt @@ -18,9 +18,9 @@ class MarkAsKnownPage(template: Template, webInterface: WebInterface): override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { val ids = freenetRequest.parameters["id", 65536]!!.split(" ") when (freenetRequest.parameters["type", 5]) { - "sone" -> ids.mapPresent(webInterface.core::getSone).forEach(webInterface.core::markSoneKnown) - "post" -> ids.mapPresent(webInterface.core::getPost).forEach(webInterface.core::markPostKnown) - "reply" -> ids.mapPresent(webInterface.core::getPostReply).forEach(webInterface.core::markReplyKnown) + "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) else -> throw RedirectException("invalid.html") } throw RedirectException(freenetRequest.parameters["returnPage", 256]!!) 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 dbcf59f..c3fabdb 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/RescuePage.kt @@ -1,5 +1,6 @@ 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 @@ -11,10 +12,10 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user control the rescue mode for a Sone. */ class RescuePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("rescue.html", template, "Page.Rescue.Title", webInterface, true) { + LoggedInPage("rescue.html", template, "Page.Rescue.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - val soneRescuer = webInterface.core.getSoneRescuer(getCurrentSone(freenetRequest.toadletContext)!!) + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { + val soneRescuer = webInterface.core.getSoneRescuer(currentSone) templateContext["soneRescuer"] = soneRescuer if (freenetRequest.isPOST) { freenetRequest.parameters["edition", 9]?.toIntOrNull()?.also { 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 aff6aaf..f296e03 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/SearchPage.kt @@ -3,11 +3,13 @@ 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 @@ -31,6 +33,7 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web private val cache: Cache, Pagination> = CacheBuilder.newBuilder().ticker(ticker).expireAfterAccess(5, MINUTES).build() override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + val startTime = System.currentTimeMillis() val phrases = try { freenetRequest.parameters["query"].emptyToNull?.parse() } catch (te: TextException) { @@ -42,25 +45,27 @@ 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).isPresent -> redirect("viewSone.html?sone=${word.removePrefix("sone://")}") - word.removePrefix("post://").let(webInterface.core::getPost).isPresent -> redirect("viewPost.html?post=${word.removePrefix("post://")}") - word.removePrefix("reply://").let(webInterface.core::getPostReply).isPresent -> redirect("viewPost.html?post=${word.removePrefix("reply://").let(webInterface.core::getPostReply).get().postId}") + 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://")}") } } } + val soneNameCache = { sone: Sone -> sone.names() }.memoize() val sonePagination = webInterface.core.sones - .scoreAndPaginate(phrases) { it.allText() } + .scoreAndPaginate(phrases) { it.allText(soneNameCache) } .apply { page = freenetRequest.parameters["sonePage"].emptyToNull?.toIntOrNull() ?: 0 } val postPagination = cache.get(phrases) { webInterface.core.sones .flatMap(Sone::getPosts) .filter { Post.FUTURE_POSTS_FILTER.apply(it) } - .scoreAndPaginate(phrases) { it.allText() } + .scoreAndPaginate(phrases) { it.allText(soneNameCache) } }.apply { page = freenetRequest.parameters["postPage"].emptyToNull?.toIntOrNull() ?: 0 } + Logger.normal(SearchPage::class.java, "Finished search for “${freenetRequest.parameters["query"]}” in ${System.currentTimeMillis() - startTime}ms.") templateContext["sonePagination"] = sonePagination templateContext["soneHits"] = sonePagination.items templateContext["postPagination"] = postPagination @@ -75,17 +80,19 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web .paginate(webInterface.core.preferences.postsPerPage) private fun Sone.names() = - listOf(name, profile.firstName, profile.middleName, profile.lastName) - .filterNotNull() - .joinToString("") + with(profile) { + listOf(name, firstName, middleName, lastName) + .filterNotNull() + .joinToString("") + } - private fun Sone.allText() = - (names() + profile.fields.map { "${it.name} ${it.value}" }.joinToString(" ", " ")).toLowerCase() + private fun Sone.allText(soneNameCache: (Sone) -> String) = + (soneNameCache(this) + profile.fields.map { "${it.name} ${it.value}" }.joinToString(" ", " ")).toLowerCase() - private fun Post.allText() = - (text + recipient.orNull()?.let { " ${it.names()}" } + webInterface.core.getReplies(id) + private fun Post.allText(soneNameCache: (Sone) -> String) = + (text + recipient.orNull()?.let { " ${soneNameCache(it)}" } + webInterface.core.getReplies(id) .filter { PostReply.FUTURE_REPLY_FILTER.apply(it) } - .map { "${it.sone.names()} ${it.text}" }.joinToString(" ", " ")).toLowerCase() + .map { "${soneNameCache(it.sone)} ${it.text}" }.joinToString(" ", " ")).toLowerCase() private fun score(text: String, phrases: Iterable): Double { val requiredPhrases = phrases.count { it.required } @@ -106,15 +113,12 @@ class SearchPage @JvmOverloads constructor(template: Template, webInterface: Web return requiredHits * 3 + optionalHits + (requiredHits - requiredPhrases) * 5 - (forbiddenHits * 2) } - private fun String.findAll(needle: String): List { - var nextIndex = indexOf(needle) - val positions = mutableListOf() - while (nextIndex != -1) { - positions += nextIndex - nextIndex = indexOf(needle, nextIndex + 1) - } - return positions - } + private fun String.findAll(needle: String) = + generateSequence(indexOf(needle).takeIf { it > -1 }) { lastPosition -> + lastPosition + .let { indexOf(needle, it + 1) } + .takeIf { it > -1 } + }.toList() private fun String.parse() = StringEscaper.parseLine(this) 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 bdc8952..758ae07 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/TrustPage.kt @@ -1,7 +1,7 @@ package net.pterodactylus.sone.web.pages +import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.isPOST -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 @@ -12,15 +12,13 @@ import net.pterodactylus.util.template.TemplateContext * 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): - SoneTemplatePage("trust.html", template, "Page.Trust.Title", webInterface, true) { +class TrustPage(template: Template, webInterface: WebInterface) : + LoggedInPage("trust.html", template, "Page.Trust.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - getCurrentSone(freenetRequest.toadletContext)?.also { currentSone -> - webInterface.core.getSone(freenetRequest.parameters["sone"]).let { sone -> - webInterface.core.trustSone(currentSone, sone) - } + webInterface.core.getSone(freenetRequest.parameters["sone"]!!)?.let { sone -> + webInterface.core.trustSone(currentSone, sone) } throw RedirectException(freenetRequest.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 01a0fde..c742542 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnbookmarkPage.kt @@ -26,8 +26,8 @@ class UnbookmarkPage(template: Template, webInterface: WebInterface): } freenetRequest.isPOST -> { freenetRequest.parameters["post", 36] - .let(webInterface.core::getPost) - .also(webInterface.core::unbookmarkPost) + ?.let(webInterface.core::getPost) + ?.also(webInterface.core::unbookmarkPost) throw RedirectException(freenetRequest.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 cc411e2..2521ef0 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnfollowSonePage.kt @@ -1,5 +1,6 @@ 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 @@ -10,15 +11,13 @@ import net.pterodactylus.util.template.TemplateContext /** * This page lets the user unfollow another Sone. */ -class UnfollowSonePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("unfollowSone.html", template, "Page.UnfollowSone.Title", webInterface, true) { +class UnfollowSonePage(template: Template, webInterface: WebInterface) : + LoggedInPage("unfollowSone.html", template, "Page.UnfollowSone.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - getCurrentSone(freenetRequest.toadletContext)!!.also { currentSone -> - freenetRequest.parameters["sone"]!!.split(Regex("[ ,]+")) - .forEach { webInterface.core.unfollowSone(currentSone, it) } - } + freenetRequest.parameters["sone"]!!.split(Regex("[ ,]+")) + .forEach { webInterface.core.unfollowSone(currentSone, it) } throw RedirectException(freenetRequest.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 42e552e..6bfabe2 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UnlikePage.kt @@ -1,5 +1,6 @@ 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 @@ -11,13 +12,13 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user unlike a [net.pterodactylus.sone.data.Post] or [net.pterodactylus.sone.data.Reply]. */ class UnlikePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("unlike.html", template, "Page.Unlike.Title", webInterface, true) { + LoggedInPage("unlike.html", template, "Page.Unlike.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { when (freenetRequest.parameters["type"]) { - "post" -> getCurrentSone(freenetRequest.toadletContext)!!.removeLikedPostId(freenetRequest.parameters["post"]!!) - "reply" -> getCurrentSone(freenetRequest.toadletContext)!!.removeLikedReplyId(freenetRequest.parameters["reply"]!!) + "post" -> currentSone.removeLikedPostId(freenetRequest.parameters["post"]!!) + "reply" -> currentSone.removeLikedReplyId(freenetRequest.parameters["reply"]!!) } throw RedirectException(freenetRequest.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 a46b272..f522c34 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UntrustPage.kt @@ -1,6 +1,6 @@ package net.pterodactylus.sone.web.pages -import net.pterodactylus.sone.utils.also +import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.utils.isPOST import net.pterodactylus.sone.utils.parameters import net.pterodactylus.sone.web.WebInterface @@ -12,16 +12,14 @@ import net.pterodactylus.util.template.TemplateContext * Page that lets the user untrust another Sone. This will remove all trust * assignments for an identity. */ -class UntrustPage(template: Template, webInterface: WebInterface): - SoneTemplatePage("untrust.html", template, "Page.Untrust.Title", webInterface, true) { +class UntrustPage(template: Template, webInterface: WebInterface) : + LoggedInPage("untrust.html", template, "Page.Untrust.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + override fun handleRequest(freenetRequest: FreenetRequest, currentSone: Sone, templateContext: TemplateContext) { if (freenetRequest.isPOST) { - getCurrentSone(freenetRequest.toadletContext)!!.also { currentSone -> - freenetRequest.parameters["sone", 44] - .let(webInterface.core::getSone) - .also { webInterface.core.untrustSone(currentSone, it) } - } + freenetRequest.parameters["sone", 44]!! + .let(webInterface.core::getSone) + ?.also { webInterface.core.untrustSone(currentSone, it) } throw RedirectException(freenetRequest.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 782c90d..4aa35ac 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/UploadImagePage.kt @@ -1,6 +1,7 @@ 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 @@ -20,12 +21,12 @@ import javax.imageio.ImageIO * Page implementation that lets the user upload an image. */ class UploadImagePage(template: Template, webInterface: WebInterface): - SoneTemplatePage("uploadImage.html", template, "Page.UploadImage.Title", webInterface, true) { + LoggedInPage("uploadImage.html", template, "Page.UploadImage.Title", webInterface) { - override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { + 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") - if (parentAlbum.sone != getCurrentSone(freenetRequest.toadletContext)) { + if (parentAlbum.sone != currentSone) { throw RedirectException("noPermission.html") } val title = freenetRequest.parameters["title", 200].emptyToNull ?: throw RedirectException("emptyImageTitle.html") @@ -39,7 +40,7 @@ class UploadImagePage(template: Template, webInterface: WebInterface): } val temporaryImage = webInterface.core.createTemporaryImage(bytes.mimeType, bytes) - webInterface.core.createImage(getCurrentSone(freenetRequest.toadletContext), parentAlbum, temporaryImage).modify().apply { + webInterface.core.createImage(currentSone, parentAlbum, temporaryImage).modify().apply { setWidth(bufferedImage.width) setHeight(bufferedImage.height) setTitle(title) 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 457e13f..910c939 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewPostPage.kt @@ -16,14 +16,14 @@ class ViewPostPage(template: Template, webInterface: WebInterface): SoneTemplatePage("viewPost.html", template, "Page.ViewPost.Title", webInterface, false) { override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { - templateContext["post"] = freenetRequest.parameters["post"].let(webInterface.core::getPost).orNull() + templateContext["post"] = freenetRequest.parameters["post"]?.let(webInterface.core::getPost) templateContext["raw"] = freenetRequest.parameters["raw"] == "true" } override fun isLinkExcepted(link: URI?) = true public override fun getPageTitle(freenetRequest: FreenetRequest) = - (freenetRequest.parameters["post"].let(webInterface.core::getPost).let { + (freenetRequest.parameters["post"]?.let(webInterface.core::getPost)?.let { if (it.text.length > 20) { it.text.substring(0..19) + "…" } else { 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 90bc147..2e175af 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/ViewSonePage.kt @@ -3,7 +3,6 @@ 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.let import net.pterodactylus.sone.utils.mapPresent import net.pterodactylus.sone.utils.paginate import net.pterodactylus.sone.utils.parameters @@ -21,7 +20,7 @@ class ViewSonePage(template: Template, webInterface: WebInterface): override fun handleRequest(freenetRequest: FreenetRequest, templateContext: TemplateContext) { templateContext["soneId"] = freenetRequest.parameters["sone"] - freenetRequest.parameters["sone"].let(webInterface.core::getSone).let { sone -> + freenetRequest.parameters["sone"]!!.let(webInterface.core::getSone)?.let { sone -> templateContext["sone"] = sone val sonePosts = sone.posts val directedPosts = webInterface.core.getDirectedPosts(sone.id) @@ -51,7 +50,7 @@ class ViewSonePage(template: Template, webInterface: WebInterface): override fun isLinkExcepted(link: URI?) = true public override fun getPageTitle(freenetRequest: FreenetRequest): String = - freenetRequest.parameters["sone"].let(webInterface.core::getSone).let { sone -> + 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") diff --git a/src/test/java/net/pterodactylus/sone/core/CoreTest.java b/src/test/java/net/pterodactylus/sone/core/CoreTest.java index cea8ed7..dbe70d5 100644 --- a/src/test/java/net/pterodactylus/sone/core/CoreTest.java +++ b/src/test/java/net/pterodactylus/sone/core/CoreTest.java @@ -22,7 +22,6 @@ import net.pterodactylus.sone.freenet.wot.OwnIdentity; import net.pterodactylus.sone.freenet.wot.event.IdentityRemovedEvent; import net.pterodactylus.util.config.Configuration; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.EventBus; @@ -74,7 +73,7 @@ public class CoreTest { Identity identity = mock(Identity.class); when(identity.getId()).thenReturn("sone-id"); Sone sone = mock(Sone.class); - when(database.getSone("sone-id")).thenReturn(Optional.of(sone)); + when(database.getSone("sone-id")).thenReturn(sone); PostReply postReply1 = mock(PostReply.class); PostReply postReply2 = mock(PostReply.class); when(sone.getReplies()).thenReturn(ImmutableSet.of(postReply1, postReply2)); diff --git a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java index 51947d1..5b94f08 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneInserterTest.java @@ -1,6 +1,5 @@ package net.pterodactylus.sone.core; -import static com.google.common.base.Optional.of; import static com.google.common.io.ByteStreams.toByteArray; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; import static java.lang.System.currentTimeMillis; @@ -62,7 +61,7 @@ public class SoneInserterTest { public void setupCore() { UpdateChecker updateChecker = mock(UpdateChecker.class); when(core.getUpdateChecker()).thenReturn(updateChecker); - when(core.getSone(anyString())).thenReturn(Optional.absent()); + when(core.getSone(anyString())).thenReturn(null); } @Test @@ -78,7 +77,7 @@ public class SoneInserterTest { when(sone.getInsertUri()).thenReturn(insertUri); when(sone.getFingerprint()).thenReturn(fingerprint); when(sone.getRootAlbum()).thenReturn(mock(Album.class)); - when(core.getSone(anyString())).thenReturn(of(sone)); + when(core.getSone(anyString())).thenReturn(sone); return sone; } @@ -223,7 +222,7 @@ public class SoneInserterTest { new SoneInserter(core, eventBus, freenetInterface, "SoneId", soneModificationDetector, 1); when(soneModificationDetector.isEligibleForInsert()).thenReturn(true); - when(core.getSone("SoneId")).thenReturn(Optional.absent()); + when(core.getSone("SoneId")).thenReturn(null); soneInserter.serviceRun(); } 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 e6bfffe..7edea06 100644 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java +++ b/src/test/java/net/pterodactylus/sone/database/memory/MemoryBookmarkDatabaseTest.java @@ -1,6 +1,5 @@ package net.pterodactylus.sone.database.memory; -import static com.google.common.base.Optional.fromNullable; import static net.pterodactylus.sone.test.Matchers.isPostWithId; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; @@ -19,7 +18,6 @@ import java.util.Set; import net.pterodactylus.sone.data.Post; -import com.google.common.base.Optional; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -42,12 +40,11 @@ public class MemoryBookmarkDatabaseTest { @Before public void setupMemoryDatabase() { when(memoryDatabase.getPost(anyString())).thenAnswer( - new Answer>() { + new Answer() { @Override - public Optional answer( + public Post answer( InvocationOnMock invocation) { - return fromNullable( - posts.get(invocation.getArguments()[0])); + return posts.get(invocation.getArguments()[0]); } }); } diff --git a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java index 352b3b2..bb62eaf 100644 --- a/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java +++ b/src/test/java/net/pterodactylus/sone/database/memory/MemoryDatabaseTest.java @@ -30,6 +30,7 @@ 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; @@ -177,37 +178,36 @@ public class MemoryDatabaseTest { firstAlbum.addImage(thirdImage); secondAlbum.addImage(secondImage); memoryDatabase.storeSone(sone); - assertThat(memoryDatabase.getPost("post1").get(), + assertThat(memoryDatabase.getPost("post1"), isPost(firstPost.getId(), 1000L, "post1", Optional.absent())); - assertThat(memoryDatabase.getPost("post2").get(), + assertThat(memoryDatabase.getPost("post2"), isPost(secondPost.getId(), 2000L, "post2", of(RECIPIENT_ID))); - assertThat(memoryDatabase.getPost("post3").isPresent(), is(false)); - assertThat(memoryDatabase.getPostReply("reply1").get(), + assertThat(memoryDatabase.getPost("post3"), nullValue()); + assertThat(memoryDatabase.getPostReply("reply1"), isPostReply("reply1", "post1", 3000L, "reply1")); - assertThat(memoryDatabase.getPostReply("reply2").get(), + assertThat(memoryDatabase.getPostReply("reply2"), isPostReply("reply2", "post2", 4000L, "reply2")); - assertThat(memoryDatabase.getPostReply("reply3").get(), + assertThat(memoryDatabase.getPostReply("reply3"), isPostReply("reply3", "post1", 5000L, "reply3")); - assertThat(memoryDatabase.getPostReply("reply4").isPresent(), - is(false)); - assertThat(memoryDatabase.getAlbum("album1").get(), + assertThat(memoryDatabase.getPostReply("reply4"), nullValue()); + assertThat(memoryDatabase.getAlbum("album1"), isAlbum("album1", null, "album1", "album-description1")); - assertThat(memoryDatabase.getAlbum("album2").get(), + assertThat(memoryDatabase.getAlbum("album2"), isAlbum("album2", null, "album2", "album-description2")); - assertThat(memoryDatabase.getAlbum("album3").get(), + assertThat(memoryDatabase.getAlbum("album3"), isAlbum("album3", "album1", "album3", "album-description3")); - assertThat(memoryDatabase.getAlbum("album4").isPresent(), is(false)); - assertThat(memoryDatabase.getImage("image1").get(), + assertThat(memoryDatabase.getAlbum("album4"), nullValue()); + assertThat(memoryDatabase.getImage("image1"), isImage("image1", 1000L, "KSK@image1", "image1", "image-description1", 16, 9)); - assertThat(memoryDatabase.getImage("image2").get(), + assertThat(memoryDatabase.getImage("image2"), isImage("image2", 2000L, "KSK@image2", "image2", "image-description2", 32, 18)); - assertThat(memoryDatabase.getImage("image3").get(), + assertThat(memoryDatabase.getImage("image3"), isImage("image3", 3000L, "KSK@image3", "image3", "image-description3", 48, 27)); - assertThat(memoryDatabase.getImage("image4").isPresent(), is(false)); + assertThat(memoryDatabase.getImage("image4"), nullValue()); } @Test @@ -266,11 +266,11 @@ public class MemoryDatabaseTest { @Test public void testBasicAlbumFunctionality() { Album newAlbum = new AlbumImpl(mock(Sone.class)); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(Optional.absent())); + assertThat(memoryDatabase.getAlbum(newAlbum.getId()), nullValue()); memoryDatabase.storeAlbum(newAlbum); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(of(newAlbum))); + assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(newAlbum)); memoryDatabase.removeAlbum(newAlbum); - assertThat(memoryDatabase.getAlbum(newAlbum.getId()), is(Optional.absent())); + assertThat(memoryDatabase.getAlbum(newAlbum.getId()), nullValue()); } private void initializeFriends() { diff --git a/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java b/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java index 0daf944..79f1974 100644 --- a/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java +++ b/src/test/java/net/pterodactylus/sone/text/SoneTextParserTest.java @@ -26,14 +26,17 @@ 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.Function; import com.google.common.base.Optional; +import kotlin.jvm.functions.Function1; import org.junit.Test; /** @@ -204,6 +207,12 @@ public class SoneTextParserTest { } @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]")); @@ -404,22 +413,21 @@ public class SoneTextParserTest { */ private static class TestSoneProvider implements SoneProvider { + @Nonnull @Override - public Function> soneLoader() { - return new Function>() { + public Function1 getSoneLoader() { + return new Function1() { @Override - public Optional apply(String soneId) { + public Sone invoke(String soneId) { return getSone(soneId); } }; } - /** - * {@inheritDoc} - */ + @Nullable @Override - public Optional getSone(final String soneId) { - return Optional.of(new IdOnlySone(soneId)); + public Sone getSone(final String soneId) { + return new IdOnlySone(soneId); } /** @@ -451,17 +459,18 @@ public class SoneTextParserTest { private static class AbsentSoneProvider extends TestSoneProvider { @Override - public Optional getSone(String soneId) { - return Optional.absent(); + public Sone getSone(String soneId) { + return null; } } private static class TestPostProvider implements PostProvider { + @Nullable @Override - public Optional getPost(final String postId) { - return Optional.of(new Post() { + public Post getPost(@Nonnull final String postId) { + return new Post() { @Override public String getId() { return postId; @@ -506,7 +515,7 @@ public class SoneTextParserTest { public Post setKnown(boolean known) { return null; } - }); + }; } @Override @@ -523,9 +532,10 @@ public class SoneTextParserTest { private static class AbsentPostProvider extends TestPostProvider { + @Nullable @Override - public Optional getPost(String postId) { - return Optional.absent(); + public Post getPost(@Nonnull String postId) { + return null; } } diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt index 5fc84f0..2d77c6e 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/CreatePostCommandTest.kt @@ -1,6 +1,5 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional import com.google.common.base.Optional.absent import com.google.common.base.Optional.of import net.pterodactylus.sone.core.Core @@ -47,7 +46,7 @@ class CreatePostCommandTest : SoneCommandTest() { @Test fun `request without text results in fcp exception`() { parameters += "Sone" to "LocalSoneId" - whenever(core.getSone("LocalSoneId")).thenReturn(Optional.of(localSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) executeCommandAndExpectFcpException() } @@ -55,7 +54,7 @@ class CreatePostCommandTest : SoneCommandTest() { fun `request with text creates post`() { parameters += "Sone" to "LocalSoneId" parameters += "Text" to "Test" - whenever(core.getSone("LocalSoneId")).thenReturn(of(localSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) val post = mock().apply { whenever(id).thenReturn("PostId") } whenever(core.createPost(localSone, absent(), "Test")).thenReturn(post) val response = command.execute(parameters) @@ -68,7 +67,7 @@ class CreatePostCommandTest : SoneCommandTest() { parameters += "Sone" to "LocalSoneId" parameters += "Text" to "Test" parameters += "Recipient" to "InvalidSoneId" - whenever(core.getSone("LocalSoneId")).thenReturn(of(localSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) executeCommandAndExpectFcpException() } @@ -77,7 +76,7 @@ class CreatePostCommandTest : SoneCommandTest() { parameters += "Sone" to "LocalSoneId" parameters += "Text" to "Test" parameters += "Recipient" to "LocalSoneId" - whenever(core.getSone("LocalSoneId")).thenReturn(of(localSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) val response = command.execute(parameters) assertThat(response.replyParameters["Message"], equalTo("Error")) assertThat(response.replyParameters["ErrorMessage"], notNullValue()) @@ -88,8 +87,8 @@ class CreatePostCommandTest : SoneCommandTest() { parameters += "Sone" to "LocalSoneId" parameters += "Text" to "Test" parameters += "Recipient" to "RemoteSoneId" - whenever(core.getSone("LocalSoneId")).thenReturn(of(localSone)) - whenever(core.getSone("RemoteSoneId")).thenReturn(of(remoteSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) val post = mock().apply { whenever(id).thenReturn("PostId") } whenever(core.createPost(localSone, of(remoteSone), "Test")).thenReturn(post) val response = command.execute(parameters) diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt index f464de4..a6e69cd 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/CreateReplyCommandTest.kt @@ -46,7 +46,7 @@ class CreateReplyCommandTest : SoneCommandTest() { private fun addValidLocalSoneParameter() { parameters += "Sone" to "LocalSoneId" - whenever(core.getSone("LocalSoneId")).thenReturn(of(localSone)) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) } @Test @@ -64,7 +64,7 @@ class CreateReplyCommandTest : SoneCommandTest() { private fun addValidPostParameter() { parameters += "Post" to "ValidPostId" - whenever(core.getPost("ValidPostId")).thenReturn(of(post)) + whenever(core.getPost("ValidPostId")).thenReturn(post) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt index 751ad24..30fc4cb 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/DeletePostCommandTest.kt @@ -38,7 +38,7 @@ class DeletePostCommandTest : SoneCommandTest() { @Test fun `request with post from remote sone returns error response`() { parameters += "Post" to "RemotePostId" - whenever(core.getPost("RemotePostId")).thenReturn(of(postFromRemoteSone)) + whenever(core.getPost("RemotePostId")).thenReturn(postFromRemoteSone) val response = command.execute(parameters) assertThat(response.replyParameters["Message"], equalTo("Error")) assertThat(response.replyParameters["ErrorCode"], equalTo("401")) @@ -47,7 +47,7 @@ class DeletePostCommandTest : SoneCommandTest() { @Test fun `request with post from local sone deletes posts`() { parameters += "Post" to "LocalPostId" - whenever(core.getPost("LocalPostId")).thenReturn(of(postFromLocalSone)) + whenever(core.getPost("LocalPostId")).thenReturn(postFromLocalSone) val response = command.execute(parameters) assertThat(response.replyParameters["Message"], equalTo("PostDeleted")) verify(core).deletePost(postFromLocalSone) diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt index 013b1c1..6920a33 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/DeleteReplyCommandTest.kt @@ -39,7 +39,7 @@ class DeleteReplyCommandTest : SoneCommandTest() { @Test fun `request with remote post reply parameter results in error response`() { parameters += "Reply" to "RemoteReplyId" - whenever(core.getPostReply("RemoteReplyId")).thenReturn(of(remotePostReply)) + whenever(core.getPostReply("RemoteReplyId")).thenReturn(remotePostReply) val response = command.execute(parameters) assertThat(response.replyParameters["Message"], equalTo("Error")) assertThat(response.replyParameters["ErrorCode"], equalTo("401")) @@ -48,7 +48,7 @@ class DeleteReplyCommandTest : SoneCommandTest() { @Test fun `request with local post reply parameter deletes reply`() { parameters += "Reply" to "RemoteReplyId" - whenever(core.getPostReply("RemoteReplyId")).thenReturn(of(localPostReply)) + whenever(core.getPostReply("RemoteReplyId")).thenReturn(localPostReply) val response = command.execute(parameters) assertThat(response.replyParameters["Message"], equalTo("ReplyDeleted")) verify(core).deleteReply(localPostReply) diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt index b7f911c..5c76c5b 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostCommandTest.kt @@ -31,7 +31,7 @@ class GetPostCommandTest : SoneCommandTest() { @Before fun setupPostWithLikesAndReplies() { - whenever(core.getPost("ValidPostId")).thenReturn(post.asOptional()) + whenever(core.getPost("ValidPostId")).thenReturn(post) whenever(core.getLikes(post)).thenReturn(setOf(sone1, sone2)) val replies = listOf(postReply1, postReply2) whenever(core.getReplies("ValidPostId")).thenReturn(replies) diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt index 72daa07..d8ab243 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostFeedCommandTest.kt @@ -3,7 +3,6 @@ package net.pterodactylus.sone.fcp import freenet.support.SimpleFieldSet import net.pterodactylus.sone.core.Core import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.equalTo @@ -58,8 +57,8 @@ class GetPostFeedCommandTest : SoneCommandTest() { private fun setupAllPostsAndReplies() { parameters += "Sone" to "ValidSoneId" whenever(localSone.id).thenReturn("ValidSoneId") - whenever(core.getSone("ValidSoneId")).thenReturn(localSone.asOptional()) - whenever(core.getSone("Friend1")).thenReturn(friend1.asOptional()) + whenever(core.getSone("ValidSoneId")).thenReturn(localSone) + whenever(core.getSone("Friend1")).thenReturn(friend1) whenever(core.getLikes(post1)).thenReturn(setOf(sone3, sone4)) whenever(core.getLikes(post1Reply1)).thenReturn(setOf(sone2, sone3)) whenever(core.getLikes(post1Reply2)).thenReturn(setOf(sone3)) diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt index 6483085..acf1824 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetPostsCommandTest.kt @@ -3,7 +3,6 @@ package net.pterodactylus.sone.fcp import freenet.support.SimpleFieldSet import net.pterodactylus.sone.core.Core import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.containsInAnyOrder import org.hamcrest.Matchers.equalTo @@ -49,8 +48,8 @@ class GetPostsCommandTest : SoneCommandTest() { whenever(core.getReplies("Post2")).thenReturn(listOf(post2Reply1, post2Reply2)) whenever(localSone.id).thenReturn("LocalSone") whenever(remoteSone.id).thenReturn("RemoteSone") - whenever(core.getSone("LocalSone")).thenReturn(localSone.asOptional()) - whenever(core.getSone("ValidSoneId")).thenReturn(remoteSone.asOptional()) + whenever(core.getSone("LocalSone")).thenReturn(localSone) + whenever(core.getSone("ValidSoneId")).thenReturn(remoteSone) whenever(remoteSone.posts).thenReturn(listOf(post2, post1)) parameters += "Sone" to "ValidSoneId" } diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt index e73160b..79aad1a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/GetSoneCommandTest.kt @@ -3,7 +3,6 @@ package net.pterodactylus.sone.fcp import net.pterodactylus.sone.core.Core import net.pterodactylus.sone.freenet.fcp.FcpException import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.nullValue @@ -43,8 +42,7 @@ class GetSoneCommandTest : SoneCommandTest() { @Test fun `request with valid Sone parameter results in response with Sone information`() { - whenever(core.getSone("SoneId")).thenReturn(sone.asOptional()) - whenever(core.getSone(null)).thenReturn(null.asOptional()) + whenever(core.getSone("SoneId")).thenReturn(sone) parameters += "Sone" to "SoneId" val replyParameters = command.execute(parameters).replyParameters assertThat(replyParameters["Message"], equalTo("Sone")) @@ -54,8 +52,8 @@ class GetSoneCommandTest : SoneCommandTest() { @Test fun `request with local sone parameter results in followed being true for friend sone`() { - whenever(core.getSone("SoneId")).thenReturn(sone.asOptional()) - whenever(core.getSone("LocalSone")).thenReturn(localSone.asOptional()) + whenever(core.getSone("SoneId")).thenReturn(sone) + whenever(core.getSone("LocalSone")).thenReturn(localSone) whenever(localSone.id).thenReturn("LocalSone") whenever(localSone.hasFriend("SoneId")).thenReturn(true) parameters += "Sone" to "SoneId" @@ -68,8 +66,8 @@ class GetSoneCommandTest : SoneCommandTest() { @Test fun `request with local sone parameter results in followed being false for non-friend sone`() { - whenever(core.getSone("SoneId")).thenReturn(sone.asOptional()) - whenever(core.getSone("LocalSone")).thenReturn(localSone.asOptional()) + whenever(core.getSone("SoneId")).thenReturn(sone) + whenever(core.getSone("LocalSone")).thenReturn(localSone) whenever(localSone.id).thenReturn("LocalSone") parameters += "Sone" to "SoneId" parameters += "LocalSone" to "LocalSone" @@ -81,8 +79,8 @@ class GetSoneCommandTest : SoneCommandTest() { @Test fun `request with remote sone as local sone parameter results in fcp exception`() { - whenever(core.getSone("SoneId")).thenReturn(sone.asOptional()) - whenever(core.getSone("RemoteSone")).thenReturn(remoteSone.asOptional()) + whenever(core.getSone("SoneId")).thenReturn(sone) + whenever(core.getSone("RemoteSone")).thenReturn(remoteSone) whenever(localSone.id).thenReturn("RemoteSone") parameters += "Sone" to "SoneId" parameters += "LocalSone" to "RemoteSone" diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt index 54f784f..6c7d40c 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LikePostCommandTest.kt @@ -23,9 +23,9 @@ class LikePostCommandTest : SoneCommandTest() { @Before fun setupPostAndSones() { - whenever(core.getPost("PostId")).thenReturn(post.asOptional()) - whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone.asOptional()) - whenever(core.getSone("LocalSoneId")).thenReturn(localSone.asOptional()) + whenever(core.getPost("PostId")).thenReturn(post) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt index 69ace0a..7b9256a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LikeReplyCommandTest.kt @@ -24,9 +24,9 @@ class LikeReplyCommandTest : SoneCommandTest() { @Before fun setupRepliesAndSones() { - whenever(core.getPostReply("ReplyId")).thenReturn(reply.asOptional()) - whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone.asOptional()) - whenever(core.getSone("LocalSoneId")).thenReturn(localSone.asOptional()) + whenever(core.getPostReply("ReplyId")).thenReturn(reply) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) } @Test diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt index 1caea96..284df69 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/LockSoneCommandTest.kt @@ -2,7 +2,6 @@ package net.pterodactylus.sone.fcp import net.pterodactylus.sone.core.Core 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 @@ -18,8 +17,8 @@ class LockSoneCommandTest : SoneCommandTest() { @Before fun setupSones() { - whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone.asOptional()) - whenever(core.getSone("LocalSoneId")).thenReturn(localSone.asOptional()) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) whenever(localSone.id).thenReturn("LocalSoneId") } diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt index aa38f88..de92612 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/SoneCommandTest.kt @@ -1,6 +1,5 @@ package net.pterodactylus.sone.fcp -import com.google.common.base.Optional import com.google.common.base.Optional.absent import freenet.support.SimpleFieldSet import net.pterodactylus.sone.core.Core @@ -39,9 +38,9 @@ abstract class SoneCommandTest { @Before fun setupCore() { - whenever(core.getSone(anyString())).thenReturn(absent()) - whenever(core.getPost(anyString())).thenReturn(absent()) - whenever(core.getPostReply(anyString())).thenReturn(absent()) + whenever(core.getSone(anyString())).thenReturn(null) + whenever(core.getPost(anyString())).thenReturn(null) + whenever(core.getPostReply(anyString())).thenReturn(null) } protected fun createSone(id: String, name: String, firstName: String, lastName: String, time: Long) = mock().apply { @@ -92,7 +91,7 @@ abstract class SoneCommandTest { fun requestWithValidRemoteSoneParameterResultsInFcpException() { parameters += "Sone" to "RemoteSoneId" - whenever(core.getSone("RemoteSoneId")).thenReturn(Optional.of(remoteSone)) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) executeCommandAndExpectFcpException() } diff --git a/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt b/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt index c002db3..77e78b3 100644 --- a/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/fcp/UnlockSoneCommandTest.kt @@ -2,7 +2,6 @@ package net.pterodactylus.sone.fcp import net.pterodactylus.sone.core.Core 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 @@ -18,8 +17,8 @@ class UnlockSoneCommandTest : SoneCommandTest() { @Before fun setupSones() { - whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone.asOptional()) - whenever(core.getSone("LocalSoneId")).thenReturn(localSone.asOptional()) + whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone) + whenever(core.getSone("LocalSoneId")).thenReturn(localSone) whenever(localSone.id).thenReturn("LocalSoneId") } diff --git a/src/test/kotlin/net/pterodactylus/sone/template/ParserFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/ParserFilterTest.kt index ac2886a..0e44568 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/ParserFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/ParserFilterTest.kt @@ -1,6 +1,5 @@ package net.pterodactylus.sone.template -import com.google.common.base.Optional.of import com.google.inject.Guice import net.pterodactylus.sone.core.Core import net.pterodactylus.sone.data.Sone @@ -40,7 +39,7 @@ class ParserFilterTest { private fun setupSone(identity: String): Sone { val sone = mock() `when`(sone.id).thenReturn(identity) - `when`(core.getSone(identity)).thenReturn(of(sone)) + `when`(core.getSone(identity)).thenReturn(sone) return sone } @@ -63,7 +62,7 @@ class ParserFilterTest { parameters.put("sone", soneOrSoneId) filter.format(templateContext, "text", parameters) val context = forClass(SoneTextParserContext::class.java) - verify(soneTextParser).parse(eq("text"), context.capture()) + verify(soneTextParser).parse(eq("text") ?: "", context.capture()) assertThat(context.value.postingSone, `is`(sone)) } diff --git a/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt index b8d6259..0920280 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt @@ -1,6 +1,5 @@ package net.pterodactylus.sone.template -import com.google.common.base.Optional import net.pterodactylus.sone.core.Core import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.Profile @@ -101,7 +100,7 @@ class RenderFilterTest { `when`(sone.profile).thenReturn(Profile(sone)) `when`(sone.name).thenReturn(name) sone.profile.firstName = firstName - `when`(core.getSone(identity)).thenReturn(Optional.of(sone)) + `when`(core.getSone(identity)).thenReturn(sone) return sone } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt index 1cbba3d..a42e5ba 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt @@ -91,12 +91,12 @@ open class TestObjects { whenever(core.preferences).thenReturn(preferences) whenever(core.updateChecker).thenReturn(updateChecker) - whenever(core.getSone(ArgumentMatchers.anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() } + whenever(core.getSone(ArgumentMatchers.anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)] } whenever(core.getLocalSone(ArgumentMatchers.anyString())).thenAnswer { localSones[it[0]] } - whenever(core.getPost(ArgumentMatchers.anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() } + whenever(core.getPost(ArgumentMatchers.anyString())).thenAnswer { (posts + newPosts)[it[0]] } whenever(core.getLikes(ArgumentMatchers.any())).then { postLikes[it[0]] ?: emptySet() } whenever(core.getLikes(ArgumentMatchers.any())).then { replyLikes[it[0]] ?: emptySet() } - whenever(core.getPostReply(ArgumentMatchers.anyString())).then { replies[it[0]].asOptional() } + whenever(core.getPostReply(ArgumentMatchers.anyString())).then { replies[it[0]] } whenever(core.getAlbum(ArgumentMatchers.anyString())).then { albums[it[0]] } whenever(core.getImage(ArgumentMatchers.anyString())).then { images[it[0]] } whenever(core.getImage(ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean())).then { images[it[0]] } 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 e4b53fd..b53cc8e 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPageTest.kt @@ -1,6 +1,8 @@ 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 @@ -24,7 +26,7 @@ class UnfollowSoneAjaxPageTest : JsonPageTest("unfollowSone.ajax", pageSupplier @Test fun `request with valid sone unfollows sone`() { - addSone(mock(), "sone-id") + addSone(mock().apply { whenever(id).thenReturn("sone-id") }) addRequestParameter("sone", "sone-id") assertThatJsonIsSuccessful() verify(core).unfollowSone(currentSone, "sone-id") 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 f76786a..b4e6570 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/EditProfilePageTest.kt @@ -86,6 +86,7 @@ class EditProfilePageTest: WebPageTest(::EditProfilePage) { addHttpRequestPart("save-profile", "true") addHttpRequestPart(fieldName, newValue.toString()) verifyRedirect("editProfile.html") { + verify(currentSone).profile = profile verify(core).touchConfiguration() assertThat(fieldAccessor(), equalTo(expectedValue)) } 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 a1fc2de..ce16c85 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/WebPageTest.kt @@ -89,11 +89,11 @@ open class WebPageTest(pageSupplier: (Template, WebInterface) -> SoneTemplatePag whenever(core.preferences).thenReturn(preferences) whenever(core.identityManager.allOwnIdentities).then { ownIdentities } whenever(core.sones).then { allSones.values } - whenever(core.getSone(anyString())).then { allSones[it[0]].asOptional() } + whenever(core.getSone(anyString())).then { allSones[it[0]] } whenever(core.localSones).then { localSones.values } whenever(core.getLocalSone(anyString())).then { localSones[it[0]] } - whenever(core.getPost(anyString())).then { allPosts[it[0]].asOptional() } - whenever(core.getPostReply(anyString())).then { allPostReplies[it[0]].asOptional() } + whenever(core.getPost(anyString())).then { allPosts[it[0]] } + whenever(core.getPostReply(anyString())).then { allPostReplies[it[0]] } whenever(core.getReplies(anyString())).then { perPostReplies[it[0]].asList() } whenever(core.getAlbum(anyString())).then { allAlbums[it[0]] } whenever(core.getImage(anyString())).then { allImages[it[0]]}