<modelVersion>4.0.0</modelVersion>
<groupId>net.pterodactylus</groupId>
<artifactId>sone</artifactId>
- <version>0.9.4</version>
+ <version>0.9.5</version>
<dependencies>
<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
+ <finalName>sone</finalName>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
- <version>0.7.1.201405082137</version>
+ <version>0.7.6.201602180812</version>
<executions>
<execution>
<id>default-prepare-agent</id>
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.pitest</groupId>
+ <artifactId>pitest-maven</artifactId>
+ <version>1.1.10</version>
+ <configuration>
+ <targetClasses>
+ <param>net.pterodactylus.sone.*</param>
+ </targetClasses>
+ <targetTests>
+ <param>net.pterodactylus.sone.*</param>
+ </targetTests>
+ </configuration>
+ </plugin>
</plugins>
</build>
</project>
String albumDescription =
getString(albumPrefix + "/Description", null);
String albumParentId = getString(albumPrefix + "/Parent", null);
- String albumImageId =
- getString(albumPrefix + "/AlbumImage", null);
if ((albumTitle == null) || (albumDescription == null)) {
throw new InvalidAlbumFound();
}
.modify()
.setTitle(albumTitle)
.setDescription(albumDescription)
- .setAlbumImage(albumImageId)
.update();
if (albumParentId != null) {
Album parentAlbum = albums.get(albumParentId);
/*
- * Sone - Core.java - Copyright © 2010–2015 David Roden
+ * Sone - Core.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 database
*/
@Inject
- public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) {
+ public Core(Configuration configuration, FreenetInterface freenetInterface, IdentityManager identityManager, UpdateChecker updateChecker, WebOfTrustUpdater webOfTrustUpdater, EventBus eventBus, Database database) {
super("Sone Core");
this.configuration = configuration;
this.freenetInterface = freenetInterface;
this.identityManager = identityManager;
this.soneDownloader = new SoneDownloaderImpl(this, freenetInterface);
this.imageInserter = new ImageInserter(freenetInterface, freenetInterface.new InsertTokenSupplier());
- this.updateChecker = new UpdateChecker(eventBus, freenetInterface);
+ this.updateChecker = updateChecker;
this.webOfTrustUpdater = webOfTrustUpdater;
this.eventBus = eventBus;
this.database = database;
configuration.getStringValue(albumPrefix + "/Title").setValue(album.getTitle());
configuration.getStringValue(albumPrefix + "/Description").setValue(album.getDescription());
configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent().equals(sone.getRootAlbum()) ? null : album.getParent().getId());
- configuration.getStringValue(albumPrefix + "/AlbumImage").setValue(album.getAlbumImage() == null ? null : album.getAlbumImage().getId());
}
configuration.getStringValue(sonePrefix + "/Albums/" + albumCounter + "/ID").setValue(null);
/* TODO - we don’t have the Sone anymore. should this happen? */
return;
}
- database.removeSone(sone.get());
+ for (PostReply postReply : sone.get().getReplies()) {
+ eventBus.post(new PostReplyRemovedEvent(postReply));
+ }
+ for (Post post : sone.get().getPosts()) {
+ eventBus.post(new PostRemovedEvent(post));
+ }
eventBus.post(new SoneRemovedEvent(sone.get()));
+ database.removeSone(sone.get());
}
/**
/*
- * Sone - FreenetInterface.java - Copyright © 2010–2015 David Roden
+ * Sone - FreenetInterface.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
/*
- * Sone - ImageInserter.java - Copyright © 2011–2015 David Roden
+ * Sone - ImageInserter.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
/*
- * Sone - Options.java - Copyright © 2010–2015 David Roden
+ * Sone - Options.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
/*
- * Sone - Preferences.java - Copyright © 2013–2015 David Roden
+ * Sone - Preferences.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - SoneDownloaderImpl.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneDownloaderImpl.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
/*
- * Sone - SoneException.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneException.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
/*
- * Sone - SoneInsertException.java - Copyright © 2011–2015 David Roden
+ * Sone - SoneInsertException.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
/*
- * Sone - SoneInserter.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneInserter.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
String parentId = albumXml.getValue("parent", null);
String title = albumXml.getValue("title", null);
String description = albumXml.getValue("description", "");
- String albumImageId = albumXml.getValue("album-image", null);
if ((id == null) || (title == null)) {
logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid album!", sone));
return null;
allImages.put(imageId, image);
}
}
- album.modify().setAlbumImage(albumImageId).update();
}
}
/*
- * Sone - SoneRescuer.java - Copyright © 2011–2015 David Roden
+ * Sone - SoneRescuer.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
/*
- * Sone - SoneUri.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneUri.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
/*
- * Sone - UpdateChecker.java - Copyright © 2011–2015 David Roden
+ * Sone - UpdateChecker.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
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.inject.Singleton;
+
import net.pterodactylus.sone.core.FreenetInterface.Fetched;
import net.pterodactylus.sone.core.event.UpdateFoundEvent;
import net.pterodactylus.sone.main.SonePlugin;
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
+@Singleton
public class UpdateChecker {
/** The logger. */
private FreenetURI currentUri;
/** The latest known edition. */
- private long latestEdition;
+ private long latestEdition = SonePlugin.getLatestEdition();
/** The current latest known version. */
- private Version currentLatestVersion = SonePlugin.VERSION;
+ private Version currentLatestVersion;
+ private final Version currentRunningVersion;
/** The release date of the latest version. */
private long latestVersionDate;
* The freenet interface to use
*/
@Inject
- public UpdateChecker(EventBus eventBus, FreenetInterface freenetInterface) {
+ public UpdateChecker(EventBus eventBus, FreenetInterface freenetInterface, Version currentVersion) {
this.eventBus = eventBus;
this.freenetInterface = freenetInterface;
+ this.currentRunningVersion = currentVersion;
+ this.currentLatestVersion = currentVersion;
}
//
* @return {@code true} if a new version was found
*/
public boolean hasLatestVersion() {
- return currentLatestVersion.compareTo(SonePlugin.VERSION) > 0;
+ return currentLatestVersion.compareTo(currentRunningVersion) > 0;
}
/**
if (version.compareTo(currentLatestVersion) > 0) {
currentLatestVersion = version;
latestVersionDate = releaseTime;
- logger.log(Level.INFO, String.format("Found new version: %s (%tc)", version, new Date(releaseTime)));
- eventBus.post(new UpdateFoundEvent(version, releaseTime, edition));
+ boolean disruptive = disruptiveVersionBetweenCurrentAndFound(properties);
+ logger.log(Level.INFO, String.format("Found new version: %s (%tc%s)", version, new Date(releaseTime), disruptive ? ", disruptive" : ""));
+ eventBus.post(new UpdateFoundEvent(version, releaseTime, edition, disruptive));
+ }
+ }
+
+ private boolean disruptiveVersionBetweenCurrentAndFound(Properties properties) {
+ for (String key : properties.stringPropertyNames()) {
+ if (key.startsWith("DisruptiveVersion/")) {
+ Version disruptiveVersion = Version.parse(key.substring("DisruptiveVersion/".length()));
+ if (disruptiveVersion.compareTo(currentRunningVersion) > 0) {
+ return true;
+ }
+ }
}
+ return false;
}
}
/*
- * Sone - WebOfTrustUpdaterImpl.java - Copyright © 2013–2015 David Roden
+ * Sone - WebOfTrustUpdaterImpl.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
/*
- * Sone - ImageEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageEvent.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
/*
- * Sone - ImageInsertAbortedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageInsertAbortedEvent.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
/*
- * Sone - ImageInsertFailedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageInsertFailedEvent.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
/*
- * Sone - ImageInsertFinishedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageInsertFinishedEvent.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
/*
- * Sone - ImageInsertStartedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageInsertStartedEvent.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
/*
- * Sone - MarkPostKnownEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - MarkPostKnownEvent.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
/*
- * Sone - MarkPostReplyKnownEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - MarkPostReplyKnownEvent.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
/*
- * Sone - MarkSoneKnownEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - MarkSoneKnownEvent.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
/*
- * Sone - NewPostFoundEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - NewPostFoundEvent.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - NewPostReplyFoundEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - NewPostReplyFoundEvent.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - NewSoneFoundEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - NewSoneFoundEvent.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
/*
- * Sone - PostEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - PostEvent.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
/*
- * Sone - PostRemovedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - PostRemovedEvent.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - PostReplyEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - PostReplyEvent.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
/*
- * Sone - PostReplyRemovedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - PostReplyRemovedEvent.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - SoneEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneEvent.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
/*
- * Sone - SoneInsertAbortedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneInsertAbortedEvent.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
/*
- * Sone - SoneInsertedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneInsertedEvent.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
/*
- * Sone - SoneInsertingEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneInsertingEvent.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
/*
- * Sone - SoneLockedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneLockedEvent.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
/*
- * Sone - SoneRemovedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneRemovedEvent.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
/*
- * Sone - SoneUnlockedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - SoneUnlockedEvent.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
/*
- * Sone - UpdateFoundEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - UpdateFoundEvent.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
*/
public class UpdateFoundEvent {
- /** The version that was found. */
private final Version version;
-
- /** The time the update was released. */
private final long releaseTime;
-
- /** The latest edition of the update page. */
private final long latestEdition;
+ private final boolean disruptive;
- /**
- * Creates a new “update found” event.
- *
- * @param version
- * The version of the update
- * @param releaseTime
- * The release time of the update
- * @param latestEdition
- * The latest edition of the update page
- */
- public UpdateFoundEvent(Version version, long releaseTime, long latestEdition) {
+ public UpdateFoundEvent(Version version, long releaseTime, long latestEdition, boolean disruptive) {
this.version = version;
this.releaseTime = releaseTime;
this.latestEdition = latestEdition;
+ this.disruptive = disruptive;
}
- //
- // ACCESSORS
- //
-
- /**
- * Returns the version of the update.
- *
- * @return The version of the update
- */
public Version version() {
return version;
}
- /**
- * Returns the release time of the update.
- *
- * @return The releae time of the update (in milliseconds since Jan 1, 1970
- * UTC)
- */
public long releaseTime() {
return releaseTime;
}
- /**
- * Returns the latest edition of the update page.
- *
- * @return The latest edition of the update page
- */
public long latestEdition() {
return latestEdition;
}
+ public boolean disruptive() {
+ return disruptive;
+ }
+
}
/*
- * Sone - Album.java - Copyright © 2011–2015 David Roden
+ * Sone - Album.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
Image moveImageDown(Image image);
/**
- * Returns the album image of this album, or {@code null} if no album image has
- * been set.
- *
- * @return The image to show when this album is listed
- */
- Image getAlbumImage();
-
- /**
* Returns whether this album contains any other albums or images.
*
* @return {@code true} if this album is empty, {@code false} otherwise
Modifier setDescription(String description);
- Modifier setAlbumImage(String imageId);
-
Album update() throws IllegalStateException;
class AlbumTitleMustNotBeEmpty extends IllegalStateException { }
/*
- * Sone - Client.java - Copyright © 2010–2015 David Roden
+ * Sone - Client.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
/*
- * Sone - Fingerprintable.java - Copyright © 2011–2015 David Roden
+ * Sone - Fingerprintable.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - Identified.java - Copyright © 2013–2015 David Roden
+ * Sone - Identified.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - Image.java - Copyright © 2011–2015 David Roden
+ * Sone - Image.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
/*
- * Sone - Post.java - Copyright © 2010–2015 David Roden
+ * Sone - Post.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
/*
- * Sone - PostReply.java - Copyright © 2010–2015 David Roden
+ * Sone - PostReply.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
/*
- * Sone - Profile.java - Copyright © 2010–2015 David Roden
+ * Sone - Profile.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
/*
- * Sone - Reply.java - Copyright © 2010–2015 David Roden
+ * Sone - Reply.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
/*
- * Sone - Sone.java - Copyright © 2010–2015 David Roden
+ * Sone - Sone.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
/*
- * Sone - TemporaryImage.java - Copyright © 2011–2015 David Roden
+ * Sone - TemporaryImage.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
/*
- * Sone - AbstractAlbumBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - AbstractAlbumBuilder.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
/*
- * Sone - AbstractImageBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - AbstractImageBuilder.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
/*
- * Sone - AbstractPostBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - AbstractPostBuilder.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
/*
- * Sone - AbstractPostReplyBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - AbstractPostReplyBuilder.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
/*
- * Sone - AbstractReplyBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - AbstractReplyBuilder.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
/*
- * Sone - AlbumBuilderImpl.java - Copyright © 2013–2015 David Roden
+ * Sone - AlbumBuilderImpl.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
/*
- * Sone - AlbumImpl.java - Copyright © 2011–2015 David Roden
+ * Sone - AlbumImpl.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 description of this album. */
private String description;
- /** The ID of the album picture. */
- private String albumImage;
-
/** Creates a new album with a random ID. */
public AlbumImpl(Sone sone) {
this(sone, UUID.randomUUID().toString());
image.getAlbum().removeImage(image);
}
image.setAlbum(this);
- if (imageIds.isEmpty() && (albumImage == null)) {
- albumImage = image.getId();
- }
if (!imageIds.contains(image.getId())) {
imageIds.add(image.getId());
images.put(image.getId(), image);
checkArgument(image.getSone().equals(sone), "image must belong to the same Sone as this album");
imageIds.remove(image.getId());
images.remove(image.getId());
- if (image.getId().equals(albumImage)) {
- if (images.isEmpty()) {
- albumImage = null;
- } else {
- albumImage = images.values().iterator().next().getId();
- }
- }
}
@Override
}
@Override
- public Image getAlbumImage() {
- if (albumImage == null) {
- return null;
- }
- return Optional.fromNullable(images.get(albumImage)).or(images.values().iterator().next());
- }
-
- @Override
public boolean isEmpty() {
return albums.isEmpty() && images.isEmpty();
}
private Optional<String> description = absent();
- private Optional<String> albumImage = absent();
-
@Override
public Modifier setTitle(String title) {
this.title = fromNullable(title);
}
@Override
- public Modifier setAlbumImage(String imageId) {
- this.albumImage = fromNullable(imageId);
- return this;
- }
-
- @Override
public Album update() throws IllegalStateException {
if (title.isPresent() && title.get().trim().isEmpty()) {
throw new AlbumTitleMustNotBeEmpty();
if (description.isPresent()) {
AlbumImpl.this.description = description.get();
}
- if (albumImage.isPresent()) {
- AlbumImpl.this.albumImage = albumImage.get();
- }
return AlbumImpl.this;
}
};
hash.putString("ID(").putString(id).putString(")");
hash.putString("Title(").putString(title).putString(")");
hash.putString("Description(").putString(description).putString(")");
- if (albumImage != null) {
- hash.putString("AlbumImage(").putString(albumImage).putString(")");
- }
/* add nested albums. */
hash.putString("Albums(");
/*
- * Sone - DefaultPostBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * Sone - DefaultPostBuilderFactory.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - DefaultPostReplyBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * Sone - DefaultPostReplyBuilderFactory.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - ImageBuilderImpl.java - Copyright © 2013–2015 David Roden
+ * Sone - ImageBuilderImpl.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
/*
- * Sone - ImageImpl.java - Copyright © 2011–2015 David Roden
+ * Sone - ImageImpl.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
/*
- * Sone - PostBuilderImpl.java - Copyright © 2013–2015 David Roden
+ * Sone - PostBuilderImpl.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - PostImpl.java - Copyright © 2010–2015 David Roden
+ * Sone - PostImpl.java - Copyright © 2010–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - PostReplyBuilderImpl.java - Copyright © 2013–2015 David Roden
+ * Sone - PostReplyBuilderImpl.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - PostReplyImpl.java - Copyright © 2010–2015 David Roden
+ * Sone - PostReplyImpl.java - Copyright © 2010–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - ReplyImpl.java - Copyright © 2011–2015 David Roden
+ * Sone - ReplyImpl.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - SoneImpl.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneImpl.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
/*
- * Sone - AlbumBuilder.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - AlbumBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - AlbumDatabase.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - AlbumProvider.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - AlbumStore.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - Database.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - DatabaseException.java - Copyright © 2013–2015 David Roden
+ * Sone - DatabaseException.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
/*
- * Sone - ImageBuilder.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - ImageBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - ImageDatabase.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - ImageProvider.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - ImageStore.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostBuilder.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostDatabase.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostProvider.java - Copyright © 2011–2015 David Roden
+ * 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
/*
- * Sone - PostReplyBuilder.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostReplyBuilderFactory.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostReplyDatabase.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostReplyProvider.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostReplyStore.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - PostStore.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - ReplyBuilder.java - Copyright © 2013–2015 David Roden
+ * 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
/*
- * Sone - SoneProvider.java - Copyright © 2011–2015 David Roden
+ * 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
/*
- * Sone - MemoryDatabase.java - Copyright © 2013–2015 David Roden
+ * Sone - MemoryDatabase.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - MemoryPost.java - Copyright © 2010–2015 David Roden
+ * Sone - MemoryPost.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
/*
- * Sone - MemoryPostBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - MemoryPostBuilder.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
/*
- * Sone - MemoryPostReply.java - Copyright © 2013–2015 David Roden
+ * Sone - MemoryPostReply.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
/*
- * Sone - MemoryPostReplyBuilder.java - Copyright © 2013–2015 David Roden
+ * Sone - MemoryPostReplyBuilder.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
/*
- * Sone - AbstractSoneCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - AbstractSoneCommand.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - CreatePostCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - CreatePostCommand.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
/*
- * Sone - CreateReplyCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - CreateReplyCommand.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
/*
- * Sone - DeletePostCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - DeletePostCommand.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
/*
- * Sone - DeleteReplyCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - DeleteReplyCommand.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
/*
- * Sone - FcpInterface.java - Copyright © 2011–2015 David Roden
+ * Sone - FcpInterface.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
/*
- * Sone - GetLocalSonesCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetLocalSonesCommand.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
/*
- * Sone - GetPostCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetPostCommand.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
/*
- * Sone - GetPostFeedCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetPostFeedCommand.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
/*
- * Sone - GetPostsCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetPostsCommand.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
/*
- * Sone - GetSoneCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetSoneCommand.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
/*
- * Sone - GetSonesCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - GetSonesCommand.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
/*
- * Sone - LikePostCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - LikePostCommand.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
/*
- * Sone - LikeReplyCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - LikeReplyCommand.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
/*
- * Sone - LockSoneCommand.java - Copyright © 2013–2015 David Roden
+ * Sone - LockSoneCommand.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
/*
- * Sone - UnlockSoneCommand.java - Copyright © 2013–2015 David Roden
+ * Sone - UnlockSoneCommand.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
/*
- * Sone - VersionCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - VersionCommand.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
/*
- * Sone - L10nFilter.java - Copyright © 2010–2015 David Roden
+ * Sone - L10nFilter.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
/*
- * Sone - PluginStoreConfigurationBackend.java - Copyright © 2010–2015 David Roden
+ * Sone - PluginStoreConfigurationBackend.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
/*
- * Sone - SimpleFieldSetBuilder.java - Copyright © 2011–2015 David Roden
+ * Sone - SimpleFieldSetBuilder.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
/*
- * Sone - AbstractCommand.java - Copyright © 2011–2015 David Roden
+ * Sone - AbstractCommand.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
/*
- * Sone - Command.java - Copyright © 2011–2015 David Roden
+ * Sone - Command.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
/*
- * Sone - FcpException.java - Copyright © 2011–2015 David Roden
+ * Sone - FcpException.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
/*
- * Sone - PluginConnector.java - Copyright © 2010–2015 David Roden
+ * Sone - PluginConnector.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
/*
- * Sone - PluginException.java - Copyright © 2010–2015 David Roden
+ * Sone - PluginException.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
/*
- * Sone - ReceivedReplyEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - ReceivedReplyEvent.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
/*
- * Sone - Context.java - Copyright © 2014–2015 David Roden
+ * Sone - Context.java - Copyright © 2014–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
/*
- * Sone - DefaultIdentity.java - Copyright © 2010–2015 David Roden
+ * Sone - DefaultIdentity.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
/*
- * Sone - DefaultOwnIdentity.java - Copyright © 2010–2015 David Roden
+ * Sone - DefaultOwnIdentity.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
/*
- * Sone - Identity.java - Copyright © 2010–2015 David Roden
+ * Sone - Identity.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
/*
- * Sone - IdentityChangeDetector.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityChangeDetector.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
/*
- * Sone - IdentityChangeEventSender.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityChangeEventSender.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
/*
- * Sone - IdentityLoader.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityLoader.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
/*
- * Sone - IdentityManagerImpl.java - Copyright © 2010–2015 David Roden
+ * Sone - IdentityManagerImpl.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
/*
- * Sone - OwnIdentity.java - Copyright © 2010–2015 David Roden
+ * Sone - OwnIdentity.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
/*
- * Sone - Trust.java - Copyright © 2010–2015 David Roden
+ * Sone - Trust.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
/*
- * Sone - WebOfTrustConnector.java - Copyright © 2010–2015 David Roden
+ * Sone - WebOfTrustConnector.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
/*
- * Sone - WebOfTrustException.java - Copyright © 2010–2015 David Roden
+ * Sone - WebOfTrustException.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
/*
- * Sone - IdentityAddedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityAddedEvent.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
/*
- * Sone - IdentityEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityEvent.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
/*
- * Sone - IdentityRemovedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityRemovedEvent.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
/*
- * Sone - IdentityUpdatedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityUpdatedEvent.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
/*
- * Sone - OwnIdentityAddedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - OwnIdentityAddedEvent.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
/*
- * Sone - OwnIdentityEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - OwnIdentityEvent.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
/*
- * Sone - OwnIdentityRemovedEvent.java - Copyright © 2013–2015 David Roden
+ * Sone - OwnIdentityRemovedEvent.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
/*
- * Sone - SonePlugin.java - Copyright © 2010–2015 David Roden
+ * Sone - SonePlugin.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 version. */
- public static final Version VERSION = new Version(0, 9, 4);
+ public static final Version VERSION = new Version(0, 9, 5);
/** The current year at time of release. */
- private static final int YEAR = 2015;
+ private static final int YEAR = 2016;
private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/";
- private static final int LATEST_EDITION = 71;
+ private static final int LATEST_EDITION = 72;
/** The logger. */
private static final Logger logger = getLogger(SonePlugin.class.getName());
return SONE_HOMEPAGE + LATEST_EDITION;
}
+ public static long getLatestEdition() {
+ return LATEST_EDITION;
+ }
+
//
// FREDPLUGIN METHODS
//
bind(Context.class).toInstance(context);
bind(getOptionalContextTypeLiteral()).toInstance(of(context));
bind(SonePlugin.class).toInstance(SonePlugin.this);
+ bind(Version.class).toInstance(VERSION);
if (startConfiguration.getBooleanValue("Developer.LoadFromFilesystem").getValue(false)) {
String path = startConfiguration.getStringValue("Developer.FilesystemPath").getValue(null);
if (path != null) {
/*
- * Sone - ListNotification.java - Copyright © 2010–2015 David Roden
+ * Sone - ListNotification.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
if (!key.equals(listNotification.key)) {
return false;
}
- if (elements.size() != listNotification.elements.size()) {
- return false;
- }
- for (int index = 0; index < elements.size(); ++index) {
- if (!elements.get(index).equals(listNotification.elements.get(index))) {
- return false;
- }
- }
- return true;
+ return elements.equals(listNotification.elements);
}
}
--- /dev/null
+/*
+ * Sone - ListNotificationFilter.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 <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.notify;
+
+import static com.google.common.collect.FluentIterable.from;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.notify.Notification;
+
+import com.google.common.base.Optional;
+
+/**
+ * Filter for {@link ListNotification}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+@Singleton
+public class ListNotificationFilter {
+
+ private final PostVisibilityFilter postVisibilityFilter;
+ private final ReplyVisibilityFilter replyVisibilityFilter;
+
+ @Inject
+ public ListNotificationFilter(@Nonnull PostVisibilityFilter postVisibilityFilter, @Nonnull ReplyVisibilityFilter replyVisibilityFilter) {
+ this.postVisibilityFilter = postVisibilityFilter;
+ this.replyVisibilityFilter = replyVisibilityFilter;
+ }
+
+ /**
+ * Filters new-post and new-reply notifications in the given list of
+ * notifications. If {@code currentSone} is <code>null</code>, new-post and
+ * new-reply notifications are removed completely. If {@code currentSone} is
+ * not {@code null}, only posts that are posted by a friend Sone or the Sone
+ * itself, and replies that are replies to posts of friend Sones or the Sone
+ * itself will be retained in the notifications.
+ *
+ * @param notifications
+ * The notifications to filter
+ * @param currentSone
+ * The current Sone, or {@code null} if not logged in
+ * @return The filtered notifications
+ */
+ @SuppressWarnings("unchecked")
+ public List<Notification> filterNotifications(Collection<? extends Notification> notifications, Sone currentSone) {
+ List<Notification> filteredNotifications = new ArrayList<Notification>();
+ for (Notification notification : notifications) {
+ if (notification.getId().equals("new-sone-notification")) {
+ if ((currentSone != null) && !currentSone.getOptions().isShowNewSoneNotifications()) {
+ continue;
+ }
+ filteredNotifications.add(notification);
+ } else if (notification.getId().equals("new-post-notification")) {
+ if (currentSone == null) {
+ continue;
+ }
+ if (!currentSone.getOptions().isShowNewPostNotifications()) {
+ continue;
+ }
+ Optional<ListNotification<Post>> filteredNotification = filterPostNotification((ListNotification<Post>) notification, currentSone);
+ if (filteredNotification.isPresent()) {
+ filteredNotifications.add(filteredNotification.get());
+ }
+ } else if (notification.getId().equals("new-reply-notification")) {
+ if (currentSone == null) {
+ continue;
+ }
+ if (!currentSone.getOptions().isShowNewReplyNotifications()) {
+ continue;
+ }
+ Optional<ListNotification<PostReply>> filteredNotification =
+ filterNewReplyNotification((ListNotification<PostReply>) notification, currentSone);
+ if (filteredNotification.isPresent()) {
+ filteredNotifications.add(filteredNotification.get());
+ }
+ } else if (notification.getId().equals("mention-notification")) {
+ Optional<ListNotification<Post>> filteredNotification = filterPostNotification((ListNotification<Post>) notification, null);
+ if (filteredNotification.isPresent()) {
+ filteredNotifications.add(filteredNotification.get());
+ }
+ } else {
+ filteredNotifications.add(notification);
+ }
+ }
+ return filteredNotifications;
+ }
+
+ /**
+ * Filters the posts of the given notification.
+ *
+ * @param postNotification
+ * The post notification
+ * @param currentSone
+ * The current Sone, or {@code null} if not logged in
+ * @return The filtered post notification, or {@link Optional#absent()} if the notification should be removed
+ */
+ @Nonnull
+ private Optional<ListNotification<Post>> filterPostNotification(@Nonnull ListNotification<Post> postNotification,
+ @Nullable Sone currentSone) {
+ List<Post> newPosts = from(postNotification.getElements()).filter(postVisibilityFilter.isVisible(currentSone)).toList();
+ if (newPosts.isEmpty()) {
+ return Optional.absent();
+ }
+ if (newPosts.size() == postNotification.getElements().size()) {
+ return Optional.of(postNotification);
+ }
+ ListNotification<Post> filteredNotification = new ListNotification<Post>(postNotification);
+ filteredNotification.setElements(newPosts);
+ filteredNotification.setLastUpdateTime(postNotification.getLastUpdatedTime());
+ return Optional.of(filteredNotification);
+ }
+
+ /**
+ * Filters the new replies of the given notification. If {@code currentSone}
+ * is {@code null}, {@code null} is returned and the notification is
+ * subsequently removed. Otherwise only replies that are replies to posts
+ * that are posted by friend Sones of the given Sone are retained; all other
+ * replies are removed.
+ *
+ * @param newReplyNotification
+ * The new-reply notification
+ * @param currentSone
+ * The current Sone, or {@code null} if not logged in
+ * @return The filtered new-reply notification, or {@code null} if the
+ * notification should be removed
+ */
+ private Optional<ListNotification<PostReply>> filterNewReplyNotification(ListNotification<PostReply> newReplyNotification,
+ @Nonnull Sone currentSone) {
+ List<PostReply> newReplies = from(newReplyNotification.getElements()).filter(replyVisibilityFilter.isVisible(currentSone)).toList();
+ if (newReplies.isEmpty()) {
+ return Optional.absent();
+ }
+ if (newReplies.size() == newReplyNotification.getElements().size()) {
+ return Optional.of(newReplyNotification);
+ }
+ ListNotification<PostReply> filteredNotification = new ListNotification<PostReply>(newReplyNotification);
+ filteredNotification.setElements(newReplies);
+ filteredNotification.setLastUpdateTime(newReplyNotification.getLastUpdatedTime());
+ return Optional.of(filteredNotification);
+ }
+
+}
+++ /dev/null
-/*
- * Sone - ListNotificationFilters.java - Copyright © 2010–2015 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.notify;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Reply;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-import net.pterodactylus.sone.freenet.wot.Trust;
-import net.pterodactylus.util.notify.Notification;
-
-import com.google.common.base.Optional;
-
-/**
- * Filter for {@link ListNotification}s.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class ListNotificationFilters {
-
- /**
- * Filters new-post and new-reply notifications in the given list of
- * notifications. If {@code currentSone} is <code>null</code>, new-post and
- * new-reply notifications are removed completely. If {@code currentSone} is
- * not {@code null}, only posts that are posted by a friend Sone or the Sone
- * itself, and replies that are replies to posts of friend Sones or the Sone
- * itself will be retained in the notifications.
- *
- * @param notifications
- * The notifications to filter
- * @param currentSone
- * The current Sone, or {@code null} if not logged in
- * @return The filtered notifications
- */
- @SuppressWarnings("unchecked")
- public static List<Notification> filterNotifications(Collection<? extends Notification> notifications, Sone currentSone) {
- List<Notification> filteredNotifications = new ArrayList<Notification>();
- for (Notification notification : notifications) {
- if (notification.getId().equals("new-sone-notification")) {
- if ((currentSone != null) && !currentSone.getOptions().isShowNewSoneNotifications()) {
- continue;
- }
- filteredNotifications.add(notification);
- } else if (notification.getId().equals("new-post-notification")) {
- if ((currentSone != null) && !currentSone.getOptions().isShowNewPostNotifications()) {
- continue;
- }
- ListNotification<Post> filteredNotification = filterNewPostNotification((ListNotification<Post>) notification, currentSone, true);
- if (filteredNotification != null) {
- filteredNotifications.add(filteredNotification);
- }
- } else if (notification.getId().equals("new-reply-notification")) {
- if ((currentSone != null) && !currentSone.getOptions().isShowNewReplyNotifications()) {
- continue;
- }
- ListNotification<PostReply> filteredNotification = filterNewReplyNotification((ListNotification<PostReply>) notification, currentSone);
- if (filteredNotification != null) {
- filteredNotifications.add(filteredNotification);
- }
- } else if (notification.getId().equals("mention-notification")) {
- ListNotification<Post> filteredNotification = filterNewPostNotification((ListNotification<Post>) notification, null, false);
- if (filteredNotification != null) {
- filteredNotifications.add(filteredNotification);
- }
- } else {
- filteredNotifications.add(notification);
- }
- }
- return filteredNotifications;
- }
-
- /**
- * Filters the new posts of the given notification. If {@code currentSone}
- * is {@code null} and {@code soneRequired} is {@code true}, {@code null} is
- * returned and the notification is subsequently removed. Otherwise only
- * posts that are posted by friend Sones of the given Sone are retained; all
- * other posts are removed.
- *
- * @param newPostNotification
- * The new-post notification
- * @param currentSone
- * The current Sone, or {@code null} if not logged in
- * @param soneRequired
- * Whether a non-{@code null} Sone in {@code currentSone} is
- * required
- * @return The filtered new-post notification, or {@code null} if the
- * notification should be removed
- */
- public static ListNotification<Post> filterNewPostNotification(ListNotification<Post> newPostNotification, Sone currentSone, boolean soneRequired) {
- if (soneRequired && (currentSone == null)) {
- return null;
- }
- List<Post> newPosts = new ArrayList<Post>();
- for (Post post : newPostNotification.getElements()) {
- if (isPostVisible(currentSone, post)) {
- newPosts.add(post);
- }
- }
- if (newPosts.isEmpty()) {
- return null;
- }
- if (newPosts.size() == newPostNotification.getElements().size()) {
- return newPostNotification;
- }
- ListNotification<Post> filteredNotification = new ListNotification<Post>(newPostNotification);
- filteredNotification.setElements(newPosts);
- filteredNotification.setLastUpdateTime(newPostNotification.getLastUpdatedTime());
- return filteredNotification;
- }
-
- /**
- * Filters the new replies of the given notification. If {@code currentSone}
- * is {@code null}, {@code null} is returned and the notification is
- * subsequently removed. Otherwise only replies that are replies to posts
- * that are posted by friend Sones of the given Sone are retained; all other
- * replies are removed.
- *
- * @param newReplyNotification
- * The new-reply notification
- * @param currentSone
- * The current Sone, or {@code null} if not logged in
- * @return The filtered new-reply notification, or {@code null} if the
- * notification should be removed
- */
- public static ListNotification<PostReply> filterNewReplyNotification(ListNotification<PostReply> newReplyNotification, Sone currentSone) {
- if (currentSone == null) {
- return null;
- }
- List<PostReply> newReplies = new ArrayList<PostReply>();
- for (PostReply reply : newReplyNotification.getElements()) {
- if (isReplyVisible(currentSone, reply)) {
- newReplies.add(reply);
- }
- }
- if (newReplies.isEmpty()) {
- return null;
- }
- if (newReplies.size() == newReplyNotification.getElements().size()) {
- return newReplyNotification;
- }
- ListNotification<PostReply> filteredNotification = new ListNotification<PostReply>(newReplyNotification);
- filteredNotification.setElements(newReplies);
- filteredNotification.setLastUpdateTime(newReplyNotification.getLastUpdatedTime());
- return filteredNotification;
- }
-
- /**
- * Filters the given posts, using {@link #isPostVisible(Sone, Post)} to
- * decide whether a post should be contained in the returned list. If
- * {@code currentSone} is not {@code null} it is used to filter out posts
- * that are from Sones that are not followed or not trusted by the given
- * Sone.
- *
- * @param posts
- * The posts to filter
- * @param currentSone
- * The current Sone (may be {@code null})
- * @return The filtered posts
- */
- public static List<Post> filterPosts(Collection<Post> posts, Sone currentSone) {
- List<Post> filteredPosts = new ArrayList<Post>();
- for (Post post : posts) {
- if (isPostVisible(currentSone, post)) {
- filteredPosts.add(post);
- }
- }
- return filteredPosts;
- }
-
- /**
- * Checks whether a post is visible to the given Sone. A post is not
- * considered visible if one of the following statements is true:
- * <ul>
- * <li>The post does not have a Sone.</li>
- * <li>The post’s {@link Post#getTime() time} is in the future.</li>
- * </ul>
- * <p>
- * If {@code post} is not {@code null} more checks are performed, and the
- * post will be invisible if:
- * </p>
- * <ul>
- * <li>The Sone of the post is not the given Sone, the given Sone does not
- * follow the post’s Sone, and the given Sone is not the recipient of the
- * post.</li>
- * <li>The trust relationship between the two Sones can not be retrieved.</li>
- * <li>The given Sone has explicitely assigned negative trust to the post’s
- * Sone.</li>
- * <li>The given Sone has not explicitely assigned negative trust to the
- * post’s Sone but the implicit trust is negative.</li>
- * </ul>
- * If none of these statements is true the post is considered visible.
- *
- * @param sone
- * The Sone that checks for a post’s visibility (may be
- * {@code null} to skip Sone-specific checks, such as trust)
- * @param post
- * The post to check for visibility
- * @return {@code true} if the post is considered visible, {@code false}
- * otherwise
- */
- public static boolean isPostVisible(Sone sone, Post post) {
- checkNotNull(post, "post must not be null");
- if (!post.isLoaded()) {
- return false;
- }
- Sone postSone = post.getSone();
- if (sone != null) {
- Trust trust = postSone.getIdentity().getTrust((OwnIdentity) sone.getIdentity());
- if (trust != null) {
- if ((trust.getExplicit() != null) && (trust.getExplicit() < 0)) {
- return false;
- }
- if ((trust.getExplicit() == null) && (trust.getImplicit() != null) && (trust.getImplicit() < 0)) {
- return false;
- }
- } else {
- /*
- * a null trust means that the trust updater has not yet
- * received a trust value for this relation. if we return false,
- * the post feed will stay empty until the trust updater has
- * received trust values. to prevent this we simply assume that
- * posts are visible if there is no trust.
- */
- }
- if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.getId().equals(post.getRecipientId().orNull())) {
- return false;
- }
- }
- if (post.getTime() > System.currentTimeMillis()) {
- return false;
- }
- return true;
- }
-
- /**
- * Checks whether a reply is visible to the given Sone. A reply is not
- * considered visible if one of the following statements is true:
- * <ul>
- * <li>The reply does not have a post.</li>
- * <li>The reply’s post does not have a Sone.</li>
- * <li>The Sone of the reply’s post is not the given Sone, the given Sone
- * does not follow the reply’s post’s Sone, and the given Sone is not the
- * recipient of the reply’s post.</li>
- * <li>The trust relationship between the two Sones can not be retrieved.</li>
- * <li>The given Sone has explicitely assigned negative trust to the post’s
- * Sone.</li>
- * <li>The given Sone has not explicitely assigned negative trust to the
- * reply’s post’s Sone but the implicit trust is negative.</li>
- * <li>The reply’s post’s {@link Post#getTime() time} is in the future.</li>
- * <li>The reply’s {@link Reply#getTime() time} is in the future.</li>
- * </ul>
- * If none of these statements is true the reply is considered visible.
- *
- * @param sone
- * The Sone that checks for a post’s visibility (may be
- * {@code null} to skip Sone-specific checks, such as trust)
- * @param reply
- * The reply to check for visibility
- * @return {@code true} if the reply is considered visible, {@code false}
- * otherwise
- */
- public static boolean isReplyVisible(Sone sone, PostReply reply) {
- checkNotNull(reply, "reply must not be null");
- Optional<Post> post = reply.getPost();
- if (!post.isPresent()) {
- return false;
- }
- if (!isPostVisible(sone, post.get())) {
- return false;
- }
- if (reply.getTime() > System.currentTimeMillis()) {
- return false;
- }
- return true;
- }
-
-}
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Singleton;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.util.notify.Notification;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Filters {@link Notification}s involving {@link Post}s.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+@Singleton
+public class PostVisibilityFilter {
+
+ /**
+ * Checks whether a post is visible to the given Sone. A post is not
+ * considered visible if one of the following statements is true:
+ * <ul>
+ * <li>The post does not have a Sone.</li>
+ * <li>The post’s {@link Post#getTime() time} is in the future.</li>
+ * </ul>
+ * <p>
+ * If {@code post} is not {@code null} more checks are performed, and the
+ * post will be invisible if:
+ * </p>
+ * <ul>
+ * <li>The Sone of the post is not the given Sone, the given Sone does not
+ * follow the post’s Sone, and the given Sone is not the recipient of the
+ * post.</li>
+ * <li>The trust relationship between the two Sones can not be retrieved.</li>
+ * <li>The given Sone has explicitely assigned negative trust to the post’s
+ * Sone.</li>
+ * <li>The given Sone has not explicitely assigned negative trust to the
+ * post’s Sone but the implicit trust is negative.</li>
+ * </ul>
+ * If none of these statements is true the post is considered visible.
+ *
+ * @param sone
+ * The Sone that checks for a post’s visibility (may be
+ * {@code null} to skip Sone-specific checks, such as trust)
+ * @param post
+ * The post to check for visibility
+ * @return {@code true} if the post is considered visible, {@code false}
+ * otherwise
+ */
+ boolean isPostVisible(@Nullable Sone sone, @Nonnull Post post) {
+ checkNotNull(post, "post must not be null");
+ if (!post.isLoaded()) {
+ return false;
+ }
+ Sone postSone = post.getSone();
+ if (sone != null) {
+ Trust trust = postSone.getIdentity().getTrust((OwnIdentity) sone.getIdentity());
+ if (trust != null) {
+ if ((trust.getExplicit() != null) && (trust.getExplicit() < 0)) {
+ return false;
+ }
+ if ((trust.getExplicit() == null) && (trust.getImplicit() != null) && (trust.getImplicit() < 0)) {
+ return false;
+ }
+ } else {
+ /*
+ * a null trust means that the trust updater has not yet
+ * received a trust value for this relation. if we return false,
+ * the post feed will stay empty until the trust updater has
+ * received trust values. to prevent this we simply assume that
+ * posts are visible if there is no trust.
+ */
+ }
+ if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.getId().equals(post.getRecipientId().orNull())) {
+ return false;
+ }
+ }
+ return post.getTime() <= System.currentTimeMillis();
+ }
+
+ @Nonnull
+ public Predicate<Post> isVisible(@Nullable final Sone currentSone) {
+ return new Predicate<Post>() {
+ @Override
+ public boolean apply(@Nullable Post post) {
+ return (post != null) && isPostVisible(currentSone, post);
+ }
+ };
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+
+/**
+ * Filter that checks a {@link PostReply} for visibility.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+@Singleton
+public class ReplyVisibilityFilter {
+
+ private final PostVisibilityFilter postVisibilityFilter;
+
+ @Inject
+ public ReplyVisibilityFilter(@Nonnull PostVisibilityFilter postVisibilityFilter) {
+ this.postVisibilityFilter = postVisibilityFilter;
+ }
+
+ /**
+ * Checks whether a reply is visible to the given Sone. A reply is not
+ * considered visible if one of the following statements is true:
+ * <ul>
+ * <li>The reply does not have a post.</li>
+ * <li>The reply’s post {@link PostVisibilityFilter#isPostVisible(Sone, Post) is not visible}.</li>
+ * <li>The reply’s {@link PostReply#getTime() time} is in the future.</li>
+ * </ul>
+ * If none of these statements is true the reply is considered visible.
+ *
+ * @param sone
+ * The Sone that checks for a post’s visibility (may be
+ * {@code null} to skip Sone-specific checks, such as trust)
+ * @param reply
+ * The reply to check for visibility
+ * @return {@code true} if the reply is considered visible, {@code false}
+ * otherwise
+ */
+ boolean isReplyVisible(@Nullable Sone sone, @Nonnull PostReply reply) {
+ checkNotNull(reply, "reply must not be null");
+ Optional<Post> post = reply.getPost();
+ if (!post.isPresent()) {
+ return false;
+ }
+ if (!postVisibilityFilter.isPostVisible(sone, post.get())) {
+ return false;
+ }
+ return reply.getTime() <= System.currentTimeMillis();
+ }
+
+ @Nonnull
+ public Predicate<PostReply> isVisible(@Nullable final Sone currentSone) {
+ return new Predicate<PostReply>() {
+ @Override
+ public boolean apply(@Nullable PostReply postReply) {
+ return (postReply != null) && isReplyVisible(currentSone, postReply);
+ }
+ };
+ }
+
+}
/*
- * Sone - AlbumAccessor.java - Copyright © 2011–2015 David Roden
+ * Sone - AlbumAccessor.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
import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Image;
import net.pterodactylus.util.template.Accessor;
import net.pterodactylus.util.template.ReflectionAccessor;
import net.pterodactylus.util.template.TemplateContext;
*/
public class AlbumAccessor extends ReflectionAccessor {
+ private final Random random = new Random();
+
/**
* {@inheritDoc}
*/
}
backlinks.add(0, new Link("imageBrowser.html?sone=" + album.getSone().getId(), SoneAccessor.getNiceName(album.getSone())));
return backlinks;
+ } else if ("albumImage".equals(member)) {
+ List<Image> images = album.getImages();
+ return images.isEmpty() ? null : images.get(random.nextInt(images.size()));
}
return super.get(templateContext, object, member);
}
/*
- * Sone - CollectionAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - CollectionAccessor.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
/*
- * Sone - CssClassNameFilter.java - Copyright © 2010–2015 David Roden
+ * Sone - CssClassNameFilter.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
/*
- * Sone - GetPagePlugin.java - Copyright © 2010–2015 David Roden
+ * Sone - GetPagePlugin.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
/*
- * Sone - HttpRequestAccessor.java - Copyright © 2011–2015 David Roden
+ * Sone - HttpRequestAccessor.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
/*
- * Sone - IdentityAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - IdentityAccessor.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
/*
- * Sone - ImageAccessor.java - Copyright © 2011–2015 David Roden
+ * Sone - ImageAccessor.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
/*
- * Sone - ImageLinkFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - ImageLinkFilter.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
/*
- * Sone - JavascriptFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - JavascriptFilter.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
/*
- * Sone - ParserFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - ParserFilter.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
import static java.lang.String.valueOf;
import static net.pterodactylus.sone.utils.NumberParsers.parseInt;
-import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
FreenetRequest request = (FreenetRequest) templateContext.get("request");
SoneTextParserContext context = new SoneTextParserContext(request, (Sone) sone);
StringWriter parsedTextWriter = new StringWriter();
- try {
- Iterable<Part> parts = soneTextParser.parse(context, new StringReader(text));
- if (length > -1) {
- int allPartsLength = 0;
- List<Part> shortenedParts = new ArrayList<Part>();
- for (Part part : parts) {
- if (part instanceof PlainTextPart) {
- String longText = ((PlainTextPart) part).getText();
- if (allPartsLength < cutOffLength) {
- if ((allPartsLength + longText.length()) > cutOffLength) {
- shortenedParts.add(new PlainTextPart(longText.substring(0, cutOffLength - allPartsLength) + "…"));
- } else {
- shortenedParts.add(part);
- }
- }
- allPartsLength += longText.length();
- } else if (part instanceof LinkPart) {
- if (allPartsLength < cutOffLength) {
- shortenedParts.add(part);
- }
- allPartsLength += ((LinkPart) part).getText().length();
- } else {
- if (allPartsLength < cutOffLength) {
+ Iterable<Part> parts = soneTextParser.parse(text, context);
+ if (length > -1) {
+ int allPartsLength = 0;
+ List<Part> shortenedParts = new ArrayList<Part>();
+ for (Part part : parts) {
+ if (part instanceof PlainTextPart) {
+ String longText = part.getText();
+ if (allPartsLength < cutOffLength) {
+ if ((allPartsLength + longText.length()) > cutOffLength) {
+ shortenedParts.add(new PlainTextPart(longText.substring(0, cutOffLength - allPartsLength) + "…"));
+ } else {
shortenedParts.add(part);
}
}
+ allPartsLength += longText.length();
+ } else if (part instanceof LinkPart) {
+ if (allPartsLength < cutOffLength) {
+ shortenedParts.add(part);
+ }
+ allPartsLength += part.getText().length();
+ } else {
+ if (allPartsLength < cutOffLength) {
+ shortenedParts.add(part);
+ }
}
- if (allPartsLength >= length) {
- parts = shortenedParts;
- }
}
- render(parsedTextWriter, parts);
- } catch (IOException ioe1) {
- /* no exceptions in a StringReader or StringWriter, ignore. */
+ if (allPartsLength >= length) {
+ parts = shortenedParts;
+ }
}
+ render(parsedTextWriter, parts);
return parsedTextWriter.toString();
}
private void render(Writer writer, PostPart postPart) {
SoneTextParser parser = new SoneTextParser(core, core);
SoneTextParserContext parserContext = new SoneTextParserContext(null, postPart.getPost().getSone());
- try {
- Iterable<Part> parts = parser.parse(parserContext, new StringReader(postPart.getPost().getText()));
- StringBuilder excerpt = new StringBuilder();
- for (Part part : parts) {
- excerpt.append(part.getText());
- if (excerpt.length() > 20) {
- int lastSpace = excerpt.lastIndexOf(" ", 20);
- if (lastSpace > -1) {
- excerpt.setLength(lastSpace);
- } else {
- excerpt.setLength(20);
- }
- excerpt.append("…");
- break;
+ Iterable<Part> parts = parser.parse(postPart.getPost().getText(), parserContext);
+ StringBuilder excerpt = new StringBuilder();
+ for (Part part : parts) {
+ excerpt.append(part.getText());
+ if (excerpt.length() > 20) {
+ int lastSpace = excerpt.lastIndexOf(" ", 20);
+ if (lastSpace > -1) {
+ excerpt.setLength(lastSpace);
+ } else {
+ excerpt.setLength(20);
}
+ excerpt.append("…");
+ break;
}
- renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), excerpt.toString(), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
- } catch (IOException ioe1) {
- /* StringReader shouldn’t throw. */
}
+ renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), excerpt.toString(), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
}
/**
/*
- * Sone - PostAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - PostAccessor.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
/*
- * Sone - ProfileAccessor.java - Copyright © 2011–2015 David Roden
+ * Sone - ProfileAccessor.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
/*
- * Sone - ReplyAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - ReplyAccessor.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
/*
- * Sone - ReplyGroupFilter.java - Copyright © 2010–2015 David Roden
+ * Sone - ReplyGroupFilter.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
/*
- * Sone - RequestChangeFilter.java - Copyright © 2010–2015 David Roden
+ * Sone - RequestChangeFilter.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
/*
- * Sone - SoneAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneAccessor.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
/*
- * Sone - SubstringFilter.java - Copyright © 2010–2015 David Roden
+ * Sone - SubstringFilter.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
/*
- * Sone - TrustAccessor.java - Copyright © 2010–2015 David Roden
+ * Sone - TrustAccessor.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
/*
- * Sone - UniqueElementFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - UniqueElementFilter.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
/*
- * Sone - UnknownDateFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - UnknownDateFilter.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
/*
- * Sone - FreenetLinkPart.java - Copyright © 2011–2015 David Roden
+ * Sone - FreenetLinkPart.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
/*
- * Sone - LinkPart.java - Copyright © 2011–2015 David Roden
+ * Sone - LinkPart.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
/*
- * Sone - Parser.java - Copyright © 2010–2015 David Roden
+ * Sone - Parser.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
package net.pterodactylus.sone.text;
-import java.io.IOException;
import java.io.Reader;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
* Interface for parsers that can create {@link Part}s from a text source
/**
* Create one or more {@link Part}s from the given text source.
*
- * @param context
- * The parser context (may be {@code null})
* @param source
* The text source
+ * @param context
+ * The parser context (may be {@code null})
* @return The parsed parts
- * @throws IOException
- * if an I/O error occurs
*/
- public Iterable<Part> parse(C context, Reader source) throws IOException;
+ @Nonnull
+ Iterable<Part> parse(@Nonnull String source, @Nullable C context);
}
/*
- * Sone - ParserContext.java - Copyright © 2010–2015 David Roden
+ * Sone - ParserContext.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
/**
* Context for the {@link Parser}. This interface needs to be implemented by
* {@link Parser}s that need to provide more information than just the text to
- * parse to {@link Parser#parse(ParserContext, java.io.Reader)}.
+ * parse to {@link Parser#parse(String, ParserContext)}.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
/*
- * Sone - Part.java - Copyright © 2010–2015 David Roden
+ * Sone - Part.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
/*
- * Sone - PartContainer.java - Copyright © 2010–2015 David Roden
+ * Sone - PartContainer.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
/*
- * Sone - PlainTextPart.java - Copyright © 2011–2015 David Roden
+ * Sone - PlainTextPart.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
/*
- * Sone - PostPart.java - Copyright © 2011–2015 David Roden
+ * Sone - PostPart.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
/*
- * Sone - SonePart.java - Copyright © 2011–2015 David Roden
+ * Sone - SonePart.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
/*
- * Sone - SoneTextParser.java - Copyright © 2010–2015 David Roden
+ * 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
import java.io.BufferedReader;
import java.io.IOException;
-import java.io.Reader;
+import java.io.StringReader;
import java.net.MalformedURLException;
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;
/**
* {@inheritDoc}
*/
+ @Nonnull
@Override
- public Iterable<Part> parse(SoneTextParserContext context, Reader source) throws IOException {
+ public Iterable<Part> parse(@Nonnull String source, @Nullable SoneTextParserContext context) {
PartContainer parts = new PartContainer();
- BufferedReader bufferedReader = (source instanceof BufferedReader) ? (BufferedReader) source : new BufferedReader(source);
+ BufferedReader bufferedReader = new BufferedReader(new StringReader(source));
try {
String line;
boolean lastLineEmpty = true;
}
lastLineEmpty = false;
}
+ } catch (IOException ioe1) {
+ // a buffered reader around a string reader should never throw.
+ throw new RuntimeException(ioe1);
} finally {
- if (bufferedReader != source) {
- Closer.close(bufferedReader);
- }
+ Closer.close(bufferedReader);
}
for (int partIndex = parts.size() - 1; partIndex >= 0; --partIndex) {
Part part = parts.getPart(partIndex);
/*
- * Sone - SoneTextParserContext.java - Copyright © 2011–2015 David Roden
+ * Sone - SoneTextParserContext.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
/*
- * Sone - TextFilter.java - Copyright © 2011–2015 David Roden
+ * Sone - TextFilter.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
/*
- * Sone - IntegerRangePredicate.java - Copyright © 2013–2015 David Roden
+ * Sone - IntegerRangePredicate.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
/*
- * Sone - AboutPage.java - Copyright © 2010–2015 David Roden
+ * Sone - AboutPage.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
/*
- * Sone - BookmarkPage.java - Copyright © 2011–2015 David Roden
+ * Sone - BookmarkPage.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
/*
- * Sone - BookmarksPage.java - Copyright © 2011–2015 David Roden
+ * Sone - BookmarksPage.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
/*
- * Sone - CreateAlbumPage.java - Copyright © 2011–2015 David Roden
+ * Sone - CreateAlbumPage.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
/*
- * Sone - CreatePostPage.java - Copyright © 2010–2015 David Roden
+ * Sone - CreatePostPage.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
/*
- * Sone - CreateReplyPage.java - Copyright © 2010–2015 David Roden
+ * Sone - CreateReplyPage.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
/*
- * Sone - CreateSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - CreateSonePage.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
/*
- * Sone - DeleteAlbumPage.java - Copyright © 2011–2015 David Roden
+ * Sone - DeleteAlbumPage.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
/*
- * Sone - DeleteImagePage.java - Copyright © 2011–2015 David Roden
+ * Sone - DeleteImagePage.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
/*
- * Sone - DeletePostPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DeletePostPage.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
/*
- * Sone - DeleteProfileFieldPage.java - Copyright © 2011–2015 David Roden
+ * Sone - DeleteProfileFieldPage.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
/*
- * Sone - DeleteReplyPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DeleteReplyPage.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
Optional<PostReply> reply = webInterface.getCore().getPostReply(replyId);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
- if (!reply.get().getSone().isLocal()) {
+ if (!reply.isPresent() || !reply.get().getSone().isLocal()) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
/*
- * Sone - DeleteSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - DeleteSonePage.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
/*
- * Sone - DismissNotificationPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DismissNotificationPage.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
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
+import com.google.common.base.Optional;
+
/**
* Page that lets the user dismiss a notification.
*
protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
String notificationId = request.getHttpRequest().getPartAsStringFailsafe("notification", 36);
- Notification notification = webInterface.getNotifications().getNotification(notificationId);
- if ((notification != null) && notification.isDismissable()) {
- notification.dismiss();
+ Optional<Notification> notification = webInterface.getNotification(notificationId);
+ if (notification.isPresent() && notification.get().isDismissable()) {
+ notification.get().dismiss();
}
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
throw new RedirectException(returnPage);
/*
- * Sone - DistrustPage.java - Copyright © 2011–2015 David Roden
+ * Sone - DistrustPage.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
/*
- * Sone - EditAlbumPage.java - Copyright © 2011–2015 David Roden
+ * Sone - EditAlbumPage.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
webInterface.getCore().touchConfiguration();
throw new RedirectException("imageBrowser.html?album=" + album.getParent().getId());
}
- String albumImageId = request.getHttpRequest().getPartAsStringFailsafe("album-image", 36);
- if (webInterface.getCore().getImage(albumImageId, false) == null) {
- albumImageId = null;
- }
- album.modify().setAlbumImage(albumImageId).update();
String title = request.getHttpRequest().getPartAsStringFailsafe("title", 100).trim();
String description = request.getHttpRequest().getPartAsStringFailsafe("description", 1000).trim();
try {
/*
- * Sone - EditImagePage.java - Copyright © 2010–2015 David Roden
+ * Sone - EditImagePage.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
/*
- * Sone - EditProfileFieldPage.java - Copyright © 2011–2015 David Roden
+ * Sone - EditProfileFieldPage.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
/*
- * Sone - EditProfilePage.java - Copyright © 2010–2015 David Roden
+ * Sone - EditProfilePage.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
/*
- * Sone - FollowSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - FollowSonePage.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
/*
- * Sone - GetImagePage.java - Copyright © 2011–2015 David Roden
+ * Sone - GetImagePage.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
/*
- * Sone - ImageBrowserPage.java - Copyright © 2011–2015 David Roden
+ * Sone - ImageBrowserPage.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
/*
- * Sone - IndexPage.java - Copyright © 2010–2015 David Roden
+ * Sone - IndexPage.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
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.notify.ListNotificationFilters;
+import net.pterodactylus.sone.notify.PostVisibilityFilter;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.collection.Pagination;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
/**
*/
public class IndexPage extends SoneTemplatePage {
- /**
- * @param template
- * The template to render
- * @param webInterface
- * The Sone web interface
- */
- public IndexPage(Template template, WebInterface webInterface) {
+ private final PostVisibilityFilter postVisibilityFilter;
+
+ public IndexPage(Template template, WebInterface webInterface, PostVisibilityFilter postVisibilityFilter) {
super("index.html", template, "Page.Index.Title", webInterface, true);
+ this.postVisibilityFilter = postVisibilityFilter;
}
//
}
}
}
- allPosts = Collections2.filter(allPosts, new Predicate<Post>() {
-
- @Override
- public boolean apply(Post post) {
- return ListNotificationFilters.isPostVisible(currentSone, post);
- }
- });
- allPosts = Collections2.filter(allPosts, Post.FUTURE_POSTS_FILTER);
+ allPosts = Collections2.filter(allPosts, postVisibilityFilter.isVisible(currentSone));
List<Post> sortedPosts = new ArrayList<Post>(allPosts);
Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
Pagination<Post> pagination = new Pagination<Post>(sortedPosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(parseInt(request.getHttpRequest().getParam("page"), 0));
/*
- * Sone - KnownSonesPage.java - Copyright © 2010–2015 David Roden
+ * Sone - KnownSonesPage.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
/*
- * Sone - LikePage.java - Copyright © 2010–2015 David Roden
+ * Sone - LikePage.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
/*
- * Sone - LockSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - LockSonePage.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
/*
- * Sone - LoginPage.java - Copyright © 2010–2015 David Roden
+ * Sone - LoginPage.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
/*
- * Sone - LogoutPage.java - Copyright © 2010–2015 David Roden
+ * Sone - LogoutPage.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
/*
- * Sone - MarkAsKnownPage.java - Copyright © 2011–2015 David Roden
+ * Sone - MarkAsKnownPage.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
/*
- * Sone - NewPage.java - Copyright © 2013–2015 David Roden
+ * Sone - NewPage.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
import java.util.List;
import java.util.Set;
-import com.google.common.collect.Collections2;
-
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.notify.ListNotificationFilters;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.notify.PostVisibilityFilter;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.collection.Pagination;
import net.pterodactylus.util.template.Template;
/**
* Page that displays all new posts and replies. The posts are filtered using
- * {@link ListNotificationFilters#filterPosts(java.util.Collection, net.pterodactylus.sone.data.Sone)}
- * and sorted by time.
+ * {@link PostVisibilityFilter#isPostVisible(Sone, Post)} and sorted by time.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
super.processTemplate(request, templateContext);
/* collect new elements from notifications. */
- Set<Post> posts = new HashSet<Post>(webInterface.getNewPosts());
- for (PostReply reply : Collections2.filter(webInterface.getNewReplies(), PostReply.HAS_POST_FILTER)) {
+ Set<Post> posts = new HashSet<Post>(webInterface.getNewPosts(getCurrentSone(request.getToadletContext(), false)));
+ for (PostReply reply : webInterface.getNewReplies(getCurrentSone(request.getToadletContext(), false))) {
posts.add(reply.getPost().get());
}
/* filter and sort them. */
- List<Post> sortedPosts = ListNotificationFilters.filterPosts(new ArrayList<Post>(posts), webInterface.getCurrentSone(request.getToadletContext(), false));
+ List<Post> sortedPosts = new ArrayList(posts);
Collections.sort(sortedPosts, Post.TIME_COMPARATOR);
/* paginate them. */
/*
- * Sone - OptionsPage.java - Copyright © 2010–2015 David Roden
+ * Sone - OptionsPage.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
/*
- * Sone - ReloadingPage.java - Copyright © 2010–2015 David Roden
+ * Sone - ReloadingPage.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
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
String path = request.getUri().getPath();
int lastSlash = path.lastIndexOf('/');
String filename = path.substring(lastSlash + 1);
- InputStream fileInputStream = new FileInputStream(new File(filesystemPath, filename));
- if (fileInputStream == null) {
+ InputStream fileInputStream;
+ try {
+ fileInputStream = new FileInputStream(new File(filesystemPath, filename));
+ } catch (FileNotFoundException fnfe1) {
return response.setStatusCode(404).setStatusText("Not found.");
}
OutputStream contentOutputStream = response.getContent();
/*
- * Sone - RescuePage.java - Copyright © 2011–2015 David Roden
+ * Sone - RescuePage.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
/*
- * Sone - SearchPage.java - Copyright © 2010–2015 David Roden
+ * Sone - SearchPage.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
/*
- * Sone - SoneTemplatePage.java - Copyright © 2010–2015 David Roden
+ * Sone - SoneTemplatePage.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
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.main.SonePlugin;
-import net.pterodactylus.sone.notify.ListNotificationFilters;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.sone.web.page.FreenetTemplatePage;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
import freenet.clients.http.SessionManager.Session;
import freenet.clients.http.ToadletContext;
import freenet.support.api.HTTPRequest;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
/**
* Base page for the Sone web interface.
*
* The path of the page
* @param template
* The template to render
- * @param webInterface
- * The Sone web interface
- */
- public SoneTemplatePage(String path, Template template, WebInterface webInterface) {
- this(path, template, null, webInterface, false);
- }
-
- /**
- * Creates a new template page for Sone that does not require the user to be
- * logged in.
- *
- * @param path
- * The path of the page
- * @param template
- * The template to render
* @param pageTitleKey
* The l10n key of the page title
* @param webInterface
templateContext.set("latestEdition", webInterface.getCore().getUpdateChecker().getLatestEdition());
templateContext.set("latestVersion", webInterface.getCore().getUpdateChecker().getLatestVersion());
templateContext.set("latestVersionTime", webInterface.getCore().getUpdateChecker().getLatestVersionDate());
- List<Notification> notifications = ListNotificationFilters.filterNotifications(webInterface.getNotifications().getNotifications(), currentSone);
+ List<Notification> notifications = new ArrayList<Notification>(webInterface.getNotifications(currentSone));
Collections.sort(notifications, Notification.CREATED_TIME_SORTER);
templateContext.set("notifications", notifications);
templateContext.set("notificationHash", notifications.hashCode());
/*
- * Sone - TrustPage.java - Copyright © 2011–2015 David Roden
+ * Sone - TrustPage.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
/*
- * Sone - UnbookmarkPage.java - Copyright © 2011–2015 David Roden
+ * Sone - UnbookmarkPage.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
/*
- * Sone - UnfollowSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnfollowSonePage.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
/*
- * Sone - UnlikePage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnlikePage.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
/*
- * Sone - UnlockSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnlockSonePage.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
/*
- * Sone - UntrustPage.java - Copyright © 2011–2015 David Roden
+ * Sone - UntrustPage.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
/*
- * Sone - UploadImagePage.java - Copyright © 2011–2015 David Roden
+ * Sone - UploadImagePage.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
if (!currentSone.equals(parent.getSone())) {
throw new RedirectException("noPermission.html");
}
- String name = request.getHttpRequest().getPartAsStringFailsafe("title", 200);
+ String name = request.getHttpRequest().getPartAsStringFailsafe("title", 200).trim();
+ if (name.length() == 0) {
+ throw new RedirectException("emptyImageTitle.html");
+ }
String description = request.getHttpRequest().getPartAsStringFailsafe("description", 4000);
HTTPUploadedFile uploadedFile = request.getHttpRequest().getUploadedFile("image");
Bucket fileBucket = uploadedFile.getData();
/*
- * Sone - ViewPostPage.java - Copyright © 2010–2015 David Roden
+ * Sone - ViewPostPage.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
/*
- * Sone - ViewSonePage.java - Copyright © 2010–2015 David Roden
+ * Sone - ViewSonePage.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
/*
- * Sone - WebInterface.java - Copyright © 2010–2015 David Roden
+ * Sone - WebInterface.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
package net.pterodactylus.sone.web;
+import static com.google.common.collect.FluentIterable.from;
import static java.util.logging.Logger.getLogger;
import static net.pterodactylus.util.template.TemplateParser.parse;
-import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent;
import net.pterodactylus.sone.main.ReparseFilter;
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.sone.notify.ListNotification;
+import net.pterodactylus.sone.notify.ListNotificationFilter;
+import net.pterodactylus.sone.notify.PostVisibilityFilter;
+import net.pterodactylus.sone.notify.ReplyVisibilityFilter;
import net.pterodactylus.sone.template.AlbumAccessor;
import net.pterodactylus.sone.template.CollectionAccessor;
import net.pterodactylus.sone.template.CssClassNameFilter;
import net.pterodactylus.util.web.RedirectPage;
import net.pterodactylus.util.web.TemplatePage;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.eventbus.Subscribe;
-import com.google.inject.Inject;
-
import freenet.clients.http.SessionManager;
import freenet.clients.http.SessionManager.Session;
import freenet.clients.http.ToadletContainer;
import freenet.l10n.BaseL10n;
import freenet.support.api.HTTPRequest;
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
/**
* Bundles functionality that a web interface of a Freenet plugin needs, e.g.
* references to l10n helpers.
/** The parser filter. */
private final ParserFilter parserFilter;
+ private final ListNotificationFilter listNotificationFilter;
+ private final PostVisibilityFilter postVisibilityFilter;
+ private final ReplyVisibilityFilter replyVisibilityFilter;
+
/** The “new Sone” notification. */
private final ListNotification<Sone> newSoneNotification;
* The Sone plugin
*/
@Inject
- public WebInterface(SonePlugin sonePlugin, Loaders loaders) {
+ public WebInterface(SonePlugin sonePlugin, Loaders loaders, ListNotificationFilter listNotificationFilter, PostVisibilityFilter postVisibilityFilter, ReplyVisibilityFilter replyVisibilityFilter) {
this.sonePlugin = sonePlugin;
this.loaders = loaders;
+ this.listNotificationFilter = listNotificationFilter;
+ this.postVisibilityFilter = postVisibilityFilter;
+ this.replyVisibilityFilter = replyVisibilityFilter;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
soneTextParser = new SoneTextParser(getCore(), getCore());
return notificationManager;
}
+ @Nonnull
+ public Optional<Notification> getNotification(@Nonnull String notificationId) {
+ return Optional.fromNullable(notificationManager.getNotification(notificationId));
+ }
+
+ @Nonnull
+ public Collection<Notification> getNotifications(@Nullable Sone currentSone) {
+ return listNotificationFilter.filterNotifications(notificationManager.getNotifications(), currentSone);
+ }
+
/**
* Returns the l10n helper of the node.
*
return ImmutableSet.<Post> builder().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).build();
}
+ @Nonnull
+ public Collection<Post> getNewPosts(@Nullable Sone currentSone) {
+ Set<Post> allNewPosts = ImmutableSet.<Post> builder()
+ .addAll(newPostNotification.getElements())
+ .addAll(localPostNotification.getElements())
+ .build();
+ return from(allNewPosts).filter(postVisibilityFilter.isVisible(currentSone)).toSet();
+ }
+
/**
* Returns the replies that have been announced as new in the
* {@link #newReplyNotification}.
return ImmutableSet.<PostReply> builder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).build();
}
+ @Nonnull
+ public Collection<PostReply> getNewReplies(@Nullable Sone currentSone) {
+ Set<PostReply> allNewReplies = ImmutableSet.<PostReply>builder()
+ .addAll(newReplyNotification.getElements())
+ .addAll(localReplyNotification.getElements())
+ .build();
+ return from(allNewReplies).filter(replyVisibilityFilter.isVisible(currentSone)).toSet();
+ }
+
/**
* Sets whether the current start of the plugin is the first start. It is
* considered a first start if the configuration file does not exist.
PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/");
pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage<FreenetRequest>("", "index.html")));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this), "Index"));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this, postVisibilityFilter), "Index"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new NewPage(newTemplate, this), "New"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateSonePage(createSoneTemplate, this), "CreateSone"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new KnownSonesPage(knownSonesTemplate, this), "KnownSones"));
private Collection<Sone> getMentionedSones(String text) {
/* we need no context to find mentioned Sones. */
Set<Sone> mentionedSones = new HashSet<Sone>();
- try {
- for (Part part : soneTextParser.parse(null, new StringReader(text))) {
- if (part instanceof SonePart) {
- mentionedSones.add(((SonePart) part).getSone());
- }
+ for (Part part : soneTextParser.parse(text, null)) {
+ if (part instanceof SonePart) {
+ mentionedSones.add(((SonePart) part).getSone());
}
- } catch (IOException ioe1) {
- logger.log(Level.WARNING, String.format("Could not parse post text: %s", text), ioe1);
}
return Collections2.filter(mentionedSones, Sone.LOCAL_SONE_FILTER);
}
@Subscribe
public void soneRemoved(SoneRemovedEvent soneRemovedEvent) {
newSoneNotification.remove(soneRemovedEvent.sone());
- for (Post post : soneRemovedEvent.sone().getPosts()) {
- removePost(post);
- }
- for (PostReply postReply : soneRemovedEvent.sone().getReplies()) {
- removeReply(postReply);
- }
}
@Subscribe
*/
@Subscribe
public void updateFound(UpdateFoundEvent updateFoundEvent) {
- newVersionNotification.getTemplateContext().set("latestVersion", updateFoundEvent.version());
- newVersionNotification.getTemplateContext().set("latestEdition", updateFoundEvent.latestEdition());
- newVersionNotification.getTemplateContext().set("releaseTime", updateFoundEvent.releaseTime());
+ newVersionNotification.set("latestVersion", updateFoundEvent.version());
+ newVersionNotification.set("latestEdition", updateFoundEvent.latestEdition());
+ newVersionNotification.set("releaseTime", updateFoundEvent.releaseTime());
+ newVersionNotification.set("disruptive", updateFoundEvent.disruptive());
notificationManager.addNotification(newVersionNotification);
}
/*
- * Sone - BookmarkAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - BookmarkAjaxPage.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
/*
- * Sone - CreatePostAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - CreatePostAjaxPage.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
/*
- * Sone - CreateReplyAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - CreateReplyAjaxPage.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
/*
- * Sone - DeletePostAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DeletePostAjaxPage.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
/*
- * Sone - DeleteProfileFieldAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - DeleteProfileFieldAjaxPage.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
/*
- * Sone - DeleteReplyAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DeleteReplyAjaxPage.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
/*
- * Sone - DismissNotificationAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - DismissNotificationAjaxPage.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
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.notify.Notification;
+import com.google.common.base.Optional;
+
/**
* AJAX page that lets the user dismiss a notification.
*
@Override
protected JsonReturnObject createJsonObject(FreenetRequest request) {
String notificationId = request.getHttpRequest().getParam("notification");
- Notification notification = webInterface.getNotifications().getNotification(notificationId);
- if (notification == null) {
+ Optional<Notification> notification = webInterface.getNotification(notificationId);
+ if (!notification.isPresent()) {
return createErrorJsonObject("invalid-notification-id");
}
- if (!notification.isDismissable()) {
+ if (!notification.get().isDismissable()) {
return createErrorJsonObject("not-dismissable");
}
- notification.dismiss();
+ notification.get().dismiss();
return createSuccessJsonObject();
}
/*
- * Sone - DistrustAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - DistrustAjaxPage.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
/*
- * Sone - EditAlbumAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - EditAlbumAjaxPage.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
/*
- * Sone - EditImageAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - EditImageAjaxPage.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
/*
- * Sone - EditProfileFieldAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - EditProfileFieldAjaxPage.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
/*
- * Sone - FollowSoneAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - FollowSoneAjaxPage.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
/*
- * Sone - GetLikesAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetLikesAjaxPage.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
/*
- * Sone - GetNotificationsAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - GetNotificationsAjaxPage.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
import java.io.IOException;
import java.io.StringWriter;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.main.SonePlugin;
-import net.pterodactylus.sone.notify.ListNotificationFilters;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.notify.Notification;
@Override
protected JsonReturnObject createJsonObject(FreenetRequest request) {
Sone currentSone = getCurrentSone(request.getToadletContext(), false);
- Collection<Notification> notifications = webInterface.getNotifications().getNotifications();
- List<Notification> filteredNotifications = ListNotificationFilters.filterNotifications(notifications, currentSone);
- Collections.sort(filteredNotifications, Notification.CREATED_TIME_SORTER);
+ List<Notification> notifications = new ArrayList<Notification>(webInterface.getNotifications(currentSone));
+ Collections.sort(notifications, Notification.CREATED_TIME_SORTER);
ArrayNode jsonNotifications = new ArrayNode(instance);
- for (Notification notification : filteredNotifications) {
+ for (Notification notification : notifications) {
jsonNotifications.add(createJsonNotification(request, notification));
}
- return createSuccessJsonObject().put("notificationHash", filteredNotifications.hashCode()).put("notifications", jsonNotifications).put("options", createJsonOptions(currentSone));
+ return createSuccessJsonObject().put("notificationHash", notifications.hashCode()).put("notifications", jsonNotifications).put("options", createJsonOptions(currentSone));
}
//
/*
- * Sone - GetPostAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetPostAjaxPage.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
/*
- * Sone - GetReplyAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetReplyAjaxPage.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
/*
- * Sone - GetStatusAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetStatusAjaxPage.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
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.notify.ListNotificationFilters;
+import net.pterodactylus.sone.notify.PostVisibilityFilter;
+import net.pterodactylus.sone.notify.ReplyVisibilityFilter;
import net.pterodactylus.sone.template.SoneAccessor;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
/**
* The “get status” AJAX handler returns all information that is necessary to
jsonSones.add(createJsonSone(sone));
}
/* load notifications. */
- List<Notification> notifications = ListNotificationFilters.filterNotifications(webInterface.getNotifications().getNotifications(), currentSone);
+ List<Notification> notifications = new ArrayList<Notification>(webInterface.getNotifications(currentSone));
Collections.sort(notifications, Notification.CREATED_TIME_SORTER);
/* load new posts. */
- Collection<Post> newPosts = webInterface.getNewPosts();
- if (currentSone != null) {
- newPosts = Collections2.filter(newPosts, new Predicate<Post>() {
-
- @Override
- public boolean apply(Post post) {
- return ListNotificationFilters.isPostVisible(currentSone, post);
- }
+ Collection<Post> newPosts = webInterface.getNewPosts(getCurrentSone(request.getToadletContext(), false));
- });
- }
ArrayNode jsonPosts = new ArrayNode(instance);
for (Post post : newPosts) {
ObjectNode jsonPost = new ObjectNode(instance);
jsonPosts.add(jsonPost);
}
/* load new replies. */
- Collection<PostReply> newReplies = webInterface.getNewReplies();
- if (currentSone != null) {
- newReplies = Collections2.filter(newReplies, new Predicate<PostReply>() {
-
- @Override
- public boolean apply(PostReply reply) {
- return ListNotificationFilters.isReplyVisible(currentSone, reply);
- }
+ Collection<PostReply> newReplies = webInterface.getNewReplies(getCurrentSone(request.getToadletContext(), false));
- });
- }
- /* remove replies to unknown posts. */
- newReplies = Collections2.filter(newReplies, PostReply.HAS_POST_FILTER);
ArrayNode jsonReplies = new ArrayNode(instance);
for (PostReply reply : newReplies) {
ObjectNode jsonReply = new ObjectNode(instance);
/*
- * Sone - GetTimesAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetTimesAjaxPage.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
String text;
long refresh;
if (age < 0) {
- text = webInterface.getL10n().getDefaultString("View.Time.InTheFuture");
+ text = webInterface.getL10n().getString("View.Time.InTheFuture");
refresh = TimeUnit.MINUTES.toMillis(5);
} else if (age < TimeUnit.SECONDS.toMillis(20)) {
- text = webInterface.getL10n().getDefaultString("View.Time.AFewSecondsAgo");
+ text = webInterface.getL10n().getString("View.Time.AFewSecondsAgo");
refresh = TimeUnit.SECONDS.toMillis(10);
} else if (age < TimeUnit.SECONDS.toMillis(45)) {
text = webInterface.getL10n().getString("View.Time.HalfAMinuteAgo");
/*
- * Sone - GetTranslationPage.java - Copyright © 2010–2015 David Roden
+ * Sone - GetTranslationPage.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
/*
- * Sone - JsonPage.java - Copyright © 2010–2015 David Roden
+ * Sone - JsonPage.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
/*
- * Sone - LikeAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - LikeAjaxPage.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
/*
- * Sone - LockSoneAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - LockSoneAjaxPage.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
/*
- * Sone - MarkAsKnownAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - MarkAsKnownAjaxPage.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
/*
- * Sone - MoveProfileFieldAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - MoveProfileFieldAjaxPage.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
/*
- * Sone - TrustAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - TrustAjaxPage.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
/*
- * Sone - UnbookmarkAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - UnbookmarkAjaxPage.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
/*
- * Sone - UnfollowSoneAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnfollowSoneAjaxPage.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
/*
- * Sone - UnlikeAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnlikeAjaxPage.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
/*
- * Sone - UnlockSoneAjaxPage.java - Copyright © 2010–2015 David Roden
+ * Sone - UnlockSoneAjaxPage.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
/*
- * Sone - UntrustAjaxPage.java - Copyright © 2011–2015 David Roden
+ * Sone - UntrustAjaxPage.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
/*
- * Sone - FreenetPage.java - Copyright © 2011–2015 David Roden
+ * Sone - FreenetPage.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - FreenetRequest.java - Copyright © 2011–2015 David Roden
+ * Sone - FreenetRequest.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - FreenetTemplatePage.java - Copyright © 2010–2015 David Roden
+ * Sone - FreenetTemplatePage.java - Copyright © 2010–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/*
- * Sone - PageToadlet.java - Copyright © 2010–2015 David Roden
+ * Sone - PageToadlet.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
/*
- * Sone - PageToadletFactory.java - Copyright © 2010–2015 David Roden
+ * Sone - PageToadletFactory.java - Copyright © 2010–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Notification.SoneRescued.Text.RememberToUnlock=Bitte denken Sie daran, die Nachrichten und Antworten dieser Sone(s) zu kontrollieren und sie danach zu entsperren!
Notification.LockedSones.Text=Diese Sones sind seit mehr als 5 Minuten gesperrt. Bitte überprüfen Sie, ob diese Sones wirklich gesperrt bleiben sollen:
Notification.NewVersion.Text=Die Version {version} vom Sone-Plugin wurde gefunden. Sie können diese Version von USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition} herunter laden.
+Notification.NewVersion.Disruptive.Text=Es wird {em}dringend empfohlen{/em}, dass Sie auf diese neue Version updaten, denn es ist möglich, dass Ihnen mit Ihrer aktuellen Version ein Haufen Inhalte entgehen!
Notification.InsertingImages.Text=Diese Bilder werden gerade nach Freenet hoch geladen:
Notification.InsertedImages.Text=Diese Bilder wurden nach Freenet hoch geladen:
Notification.ImageInsertFailed.Text=Diese Bilder konnten nicht nach Freenet hoch geladen werden:
Notification.SoneRescued.Text.RememberToUnlock=Please remember to control the posts and replies you have given and don’t forget to unlock your Sones!
Notification.LockedSones.Text=The following Sones have been locked for more than 5 minutes. Please check if you really want to keep these Sones locked:
Notification.NewVersion.Text=Version {version} of the Sone plugin was found. Download it from USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=It is {em}highly recommended{/em} that you update to this version as it may be possible that you are missing a lot of content with your current version!
Notification.InsertingImages.Text=The following images are being inserted:
Notification.InsertedImages.Text=The following images have been inserted:
Notification.ImageInsertFailed.Text=The following images could not be inserted:
View.Search.Button.Search=Buscar
-View.CreateSone.Text.WotIdentityRequired=Para crear un Sone necesitas una identidad del {link} plugin Web of Trust{/link}.
+View.CreateSone.Text.WotIdentityRequired=Para crear un Sone necesitas una identidad del {link}plugin Web of Trust{/link}.
View.CreateSone.Select.Default=Selecciona una identidad
View.CreateSone.Text.NoIdentities=No tienes ninguna identidad de Web of Trust. Por favor, ve al {link}plugin Web of Trust{/link} y crea una identidad.
View.CreateSone.Text.NoNonSoneIdentities=No tienes ninguna identidad de Web of Trust que no tenga ya un Sone. Usa alguna de las identidades restantes para crear un nuevo Sone o ve al {link}plugin Web of Trust{/link} para crear una nueva identidad.
Notification.SoneRescued.Text.RememberToUnlock=Por favor, recuerda controlar las publicaciones y respuestas que has dado y no olvides desbloquear tus Sones!
Notification.LockedSones.Text=Los siguientes Sone han estado bloqueados durante más de 5 minutos. Por favor, comprueva si realmente quieres mantenerlos bloqueados:
Notification.NewVersion.Text=La versión {version} del plugin Sone fue encontrada. Descargala de USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=Es {em}muy recomendable{/em} que se actualice a la nueva version tan pronto como sea posible ya que pueden haber nuevas herramientas incompatibles con la actual!
Notification.InsertingImages.Text=Las siguientes imágenes están siendo insertadas:
Notification.InsertedImages.Text=Las siguientes imágenes han sido insertadas:
Notification.ImageInsertFailed.Text=Las siguientes imágenes no han podido ser insertadas:
Notification.SoneRescued.Text.RememberToUnlock=Veuillez vous souvenir de contrôler les messages et réponses que vous avez donnés et n'oubliez pas de déverrouiller vos Sones!
Notification.LockedSones.Text=Les Sones suivants ont été verrouillés pour une durée de plus de 5 minutes. Veuillez vérifier si vous voulez vraiment garder ces Sones bloqués:
Notification.NewVersion.Text=La version ${version} du plugin Sone a été trouvée. Téléchargez la depuis USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=Il est {en}fortement recommandé{/en} que vous mettiez à jour vers cette version, car il est possible que vous manquiez beaucoup de contenu avec la version actuelle!
Notification.InsertingImages.Text=Les images suivantes sont en cours d'insertion:
Notification.InsertedImages.Text=Les images suivantes ont été insérées:
Notification.ImageInsertFailed.Text=Les images suivantes ne peuvent être insérées:
Notification.SoneRescued.Text.RememberToUnlock=投稿や返信を確認の上、ロックを解除するのを忘れないようにしてください。
Notification.LockedSones.Text=次のSoneは5分以上ロック状態になっています。故意にロック中であるかを確認してください:
Notification.NewVersion.Text=Soneの新しいバージョン{version}があります。USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}よりダウンロードしてください。
+Notification.NewVersion.Disruptive.Text=It is {em}highly recommended{/em} that you update to this version as it may be possible that you are missing a lot of content with your current version!
Notification.InsertingImages.Text=次の画像がインサート中です:
Notification.InsertedImages.Text=次の画像のインサートされました:
Notification.ImageInsertFailed.Text=次の画像のインサートに失敗しました:
Notification.SoneIsInserting.Text=あなたのSone sone://{0}は現在インサート中です。
Notification.SoneIsInserted.Text=あなたのSone sone://{0}は{1,number}{1,choice,0#秒|1#秒|1<秒}でインサートされました。
Notification.SoneInsertAborted.Text=あなたのSone sone://{0}のインサートに失敗しました。
-# 60, 100
+# 60, 100, 458
Notification.SoneRescued.Text.RememberToUnlock=Husk å kontroller innlegg og svar du har publisert og ikke glem å lås opp dine Soner!
Notification.LockedSones.Text=De følgende Sonene har vært låst i mer enn 5 minutter. Vennligst sjekk om du virkelig ønsker å beholde disse Sonene låst:
Notification.NewVersion.Text=Utgave {version} av sone-tillegget ble funnet. Last det ned fra USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=It is {em}highly recommended{/em} that you update to this version as it may be possible that you are missing a lot of content with your current version!
Notification.InsertingImages.Text=De følgende bildene blir lastet opp:
Notification.InsertedImages.Text=De følgende bildene har blitt lastet opp:
Notification.ImageInsertFailed.Text=De følgende bildene kunne ikke bli innsatt:
Notification.SoneIsInserting.Text=Your Sone sone://{0} is now being inserted.
Notification.SoneIsInserted.Text=Your Sone sone://{0} has been inserted in {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Your Sone sone://{0} could not be inserted.
-# 60, 100, 120-121, 308-310, 312-314, 463-465
+# 60, 100, 120-121, 308-310, 312-314, 458, 463-465
Notification.SoneRescued.Text.RememberToUnlock=Należy pamiętać o zarządzaniu napisanymi postami i odpowiedziami oraz nie zapomnieć o odblokowaniu swoich Sone!
Notification.LockedSones.Text=Następujące Sone są zablokowane od ponad 5 minut. Sprawdź czy chcesz, żeby pozostały zablokowane.
Notification.NewVersion.Text=Znaleziono wersję {version}wtyczki Sone. Ściągnij ją z USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=It is {em}highly recommended{/em} that you update to this version as it may be possible that you are missing a lot of content with your current version!
Notification.InsertingImages.Text=Ładowane są następujące obrazy:
Notification.InsertedImages.Text=Załadowano nastepujące obrazy:
Notification.ImageInsertFailed.Text=Nie można załadowac następujących obrazów:
Notification.SoneIsInserting.Text=Twoje Sone sone://{0} jest w tej chili wysyłane.
Notification.SoneIsInserted.Text=Twoje sone://{0} zostało wysłane w {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Twoje Sone sone://{0} nie mogło zostać wysłane.
+# 458
Notification.SoneRescued.Text.RememberToUnlock=Пожалуйста, не забывайте контролировать сообщения и ответы, которые вы дали и не забывайте разблокировать ваши Sone!
Notification.LockedSones.Text=Следующие Sone были заблокированы более 5 минут. Пожалуйста, проверьте, действительно ли вы хотите держать эти Sone заблокированными:
Notification.NewVersion.Text=Версия {version} дополнения Sone была найдена. Загрузите ее из USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
+Notification.NewVersion.Disruptive.Text=It is {em}highly recommended{/em} that you update to this version as it may be possible that you are missing a lot of content with your current version!
Notification.InsertingImages.Text=Следующие изображения выгружаются:
Notification.InsertedImages.Text=Следующие изображения были выгружены:
Notification.ImageInsertFailed.Text=Следующие изображения не могут быть выгружены:
Notification.SoneIsInserting.Text=Your Sone sone://{0} is now being inserted.
Notification.SoneIsInserted.Text=Your Sone sone://{0} has been inserted in {1,number} {1,choice,0#seconds|1#second|1<seconds}.
Notification.SoneInsertAborted.Text=Your Sone sone://{0} could not be inserted.
-# 60, 100, 120-121, 308-310, 312-314, 463-465
+# 60, 100, 120-121, 308-310, 312-314, 458, 463-465
sone.find(".post#post-" + postId + " .create-reply .sender").hide();
sone.find(".post#post-" + postId + " .create-reply .select-sender").show();
sone.find(".post#post-" + postId + " .create-reply :input[name=sender]").val(getCurrentSoneId());
+ updateReplyTimes(replyId);
} else {
alert(error);
}
<form method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% returnPage|html>" />
- <input type="hidden" name="post" value="<% post.id|html>" />
+ <input type="hidden" name="post" value="<% post|html>" />
<button type="submit" name="confirmDelete" value="1"><%= Page.DeletePost.Button.Yes|l10n|html></button>
<button type="submit" name="abortDelete" value="1"><%= Page.DeletePost.Button.No|l10n|html></button>
</form>
<form method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% returnPage|html>" />
- <input type="hidden" name="reply" value="<% reply.id|html>" />
+ <input type="hidden" name="reply" value="<% reply|html>" />
<button type="submit" name="confirmDelete" value="1"><%= Page.DeleteReply.Button.Yes|l10n|html></button>
<button type="submit" name="abortDelete" value="1"><%= Page.DeleteReply.Button.No|l10n|html></button>
</form>
<input type="hidden" name="formPassword" value="<%formPassword|html>" />
<input type="hidden" name="album" value="<%album.id|html>" />
- <%if ! album.images.empty>
- <div>
- <label for="album-image"><%= Page.ImageBrowser.Album.Label.AlbumImage|l10n|html></label>
- <select name="album-image">
- <option disabled="disabled"><%= Page.ImageBrowser.Album.AlbumImage.Choose|l10n|html></option>
- <%foreach album.images image>
- <option value="<% image.id|html>"<%if album.albumImage.id|match value=image.id> selected="selected"<%/if>><% image.title|html></option>
- <%/foreach>
- </select>
- </div>
- <%/if>
<div>
<label for="title"><%= Page.ImageBrowser.Album.Label.Title|l10n|html></label>
<input type="text" name="title" value="<%album.title|html>" />
+++ /dev/null
-<album>
- <id><% album.id|xml></id>
- <name><% album.name|xml></name>
- <description><% album.description|xml></description>
- <albums>
- <%foreach album.albums album>
- <%include insert/include/album.xml>
- <%/foreach>
- </albums>
- <images>
- <%foreach album.images image>
- <image>
- <id><% image.id|xml></id>
- <creation-time><% image.creationTime|xml></creation-time>
- <key><% image.key|xml></key>
- <width><% image.width|xml></width>
- <height><% image.height|xml></height>
- <title><% image.title|xml></title>
- <description><% image.description|xml></description>
- </image>
- <%/foreach>
- </images>
-</album>
<div class="text"><%= Notification.NewVersion.Text|l10n|replace needle=="{version}" replacement=latestVersion|replace needle=="{edition}" replacement=latestEdition|parse sone=="nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"></div>
+<%if disruptive>
+ <div class="text"><%= Notification.NewVersion.Disruptive.Text|l10n|html|replace needle=="{em}" replacement=="<em>"|replace needle=="{/em}" replacement=="</em>"></div>
+<%/if>
/*
- * Sone - Matchers.java - Copyright © 2013–2015 David Roden
+ * Sone - Matchers.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
public static Matcher<Album> isAlbum(final String albumId,
final String parentAlbumId,
- final String title, final String albumDescription,
- final String imageId) {
+ final String title, final String albumDescription) {
return new TypeSafeDiagnosingMatcher<Album>() {
@Override
protected boolean matchesSafely(Album album,
.appendValue(album.getDescription());
return false;
}
- if (imageId == null) {
- if (album.getAlbumImage() != null) {
- mismatchDescription.appendText("has album image");
- return false;
- }
- } else {
- if (album.getAlbumImage() == null) {
- mismatchDescription.appendText("has no album image");
- return false;
- }
- if (!album.getAlbumImage().getId().equals(imageId)) {
- mismatchDescription.appendText("has album image ")
- .appendValue(album.getAlbumImage().getId());
- return false;
- }
- }
return true;
}
description.appendText(", has title ").appendValue(title);
description.appendText(", has description ")
.appendValue(albumDescription);
- if (imageId == null) {
- description.appendText(", has no album image");
- } else {
- description.appendText(", has album image ")
- .appendValue(imageId);
- }
}
};
}
return description;
}
});
- when(album.getAlbumImage()).thenAnswer(new Answer<Image>() {
- @Override
- public Image answer(InvocationOnMock invocation) {
- if (imageId == null) {
- return null;
- }
- Image image = mock(Image.class);
- when(image.getId()).thenReturn(imageId);
- return image;
- }
- });
when(album.getAlbums()).thenReturn(albums);
when(album.getImages()).thenReturn(images);
doAnswer(new Answer<Void>() {
}
@Override
- public Modifier setAlbumImage(String imageId) {
- TestAlbumBuilder.this.imageId = imageId;
- return this;
- }
-
- @Override
public Album update() throws IllegalStateException {
return album;
}
albumBuilderFactory);
assertThat(topLevelAlbums, hasSize(2));
Album firstAlbum = topLevelAlbums.get(0);
- assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1", "I1"));
+ assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1"));
assertThat(firstAlbum.getAlbums(), emptyIterable());
assertThat(firstAlbum.getImages(), emptyIterable());
Album secondAlbum = topLevelAlbums.get(1);
- assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2", null));
+ assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2"));
assertThat(secondAlbum.getAlbums(), hasSize(1));
assertThat(secondAlbum.getImages(), emptyIterable());
Album thirdAlbum = secondAlbum.getAlbums().get(0);
- assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3", "I3"));
+ assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3"));
assertThat(thirdAlbum.getAlbums(), emptyIterable());
assertThat(thirdAlbum.getImages(), emptyIterable());
}
package net.pterodactylus.sone.core;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import net.pterodactylus.sone.core.Core.MarkPostKnown;
import net.pterodactylus.sone.core.Core.MarkReplyKnown;
+import net.pterodactylus.sone.core.event.PostRemovedEvent;
+import net.pterodactylus.sone.core.event.PostReplyRemovedEvent;
+import net.pterodactylus.sone.core.event.SoneRemovedEvent;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.database.Database;
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.IdentityManager;
+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;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.junit.Test;
+import org.mockito.InOrder;
/**
* Unit test for {@link Core} and its subclasses.
verify(core).markReplyKnown(eq(postReply));
}
+ @Test
+ public void removingAnIdentitySendsRemovalEventsForAllSoneElements() {
+ // given
+ Configuration configuration = mock(Configuration.class);
+ FreenetInterface freenetInterface = mock(FreenetInterface.class);
+ IdentityManager identityManager = mock(IdentityManager.class);
+ SoneDownloader soneDownloader = mock(SoneDownloader.class);
+ ImageInserter imageInserter = mock(ImageInserter.class);
+ UpdateChecker updateChecker = mock(UpdateChecker.class);
+ WebOfTrustUpdater webOfTrustUpdater = mock(WebOfTrustUpdater.class);
+ EventBus eventBus = mock(EventBus.class);
+ Database database = mock(Database.class);
+ Core core = new Core(configuration, freenetInterface, identityManager, soneDownloader, imageInserter, updateChecker, webOfTrustUpdater, eventBus, database);
+ OwnIdentity ownIdentity = mock(OwnIdentity.class);
+ 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));
+ PostReply postReply1 = mock(PostReply.class);
+ PostReply postReply2 = mock(PostReply.class);
+ when(sone.getReplies()).thenReturn(ImmutableSet.of(postReply1, postReply2));
+ Post post1 = mock(Post.class);
+ Post post2 = mock(Post.class);
+ when(sone.getPosts()).thenReturn(ImmutableList.of(post1, post2));
+
+ // when
+ core.identityRemoved(new IdentityRemovedEvent(ownIdentity, identity));
+
+ // then
+ InOrder inOrder = inOrder(eventBus, database);
+ inOrder.verify(eventBus).post(argThat(isPostReplyRemoved(postReply1)));
+ inOrder.verify(eventBus).post(argThat(isPostReplyRemoved(postReply2)));
+ inOrder.verify(eventBus).post(argThat(isPostRemoved(post1)));
+ inOrder.verify(eventBus).post(argThat(isPostRemoved(post2)));
+ inOrder.verify(eventBus).post(argThat(isSoneRemoved(sone)));
+ inOrder.verify(database).removeSone(sone);
+ }
+
+ private Matcher<Object> isPostRemoved(final Post post) {
+ return new TypeSafeDiagnosingMatcher<Object>() {
+ @Override
+ protected boolean matchesSafely(Object item, Description mismatchDescription) {
+ if (!(item instanceof PostRemovedEvent)) {
+ mismatchDescription.appendText("is not PostRemovedEvent");
+ return false;
+ }
+ if (((PostRemovedEvent) item).post() != post) {
+ mismatchDescription.appendText("post is ").appendValue(((PostRemovedEvent) item).post());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is PostRemovedEvent and post is ").appendValue(post);
+ }
+ };
+ }
+
+ private Matcher<Object> isPostReplyRemoved(final PostReply postReply) {
+ return new TypeSafeDiagnosingMatcher<Object>() {
+ @Override
+ protected boolean matchesSafely(Object item, Description mismatchDescription) {
+ if (!(item instanceof PostReplyRemovedEvent)) {
+ mismatchDescription.appendText("is not PostReplyRemovedEvent");
+ return false;
+ }
+ if (((PostReplyRemovedEvent) item).postReply() != postReply) {
+ mismatchDescription.appendText("post reply is ").appendValue(((PostReplyRemovedEvent) item).postReply());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is PostReplyRemovedEvent and post is ").appendValue(postReply);
+ }
+ };
+ }
+
+ private Matcher<Object> isSoneRemoved(final Sone sone) {
+ return new TypeSafeDiagnosingMatcher<Object>() {
+ @Override
+ protected boolean matchesSafely(Object item, Description mismatchDescription) {
+ if (!(item instanceof SoneRemovedEvent)) {
+ mismatchDescription.appendText("is not SoneRemovedEvent");
+ return false;
+ }
+ if (((SoneRemovedEvent) item).sone() != sone) {
+ mismatchDescription.appendText("sone is ").appendValue(((SoneRemovedEvent) item).sone());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("is SoneRemovedEvent and sone is ").appendValue(sone);
+ }
+ };
+ }
+
}
@Before
public void setupAlbum() {
final Album album = SoneParserTest.this.album;
- when(album.getAlbumImage()).thenReturn(mock(Image.class));
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) {
final Modifier albumModifier = new Modifier() {
private String title = album.getTitle();
private String description = album.getDescription();
- private String imageId = album.getAlbumImage().getId();
@Override
public Modifier setTitle(String title) {
}
@Override
- public Modifier setAlbumImage(String imageId) {
- this.imageId = imageId;
- return this;
- }
-
- @Override
public Album update() throws IllegalStateException {
when(album.getTitle()).thenReturn(title);
when(album.getDescription()).thenReturn(description);
- Image image = mock(Image.class);
- when(image.getId()).thenReturn(imageId);
- when(album.getAlbumImage()).thenReturn(image);
return album;
}
};
package net.pterodactylus.sone.core;
import static java.lang.Long.MAX_VALUE;
-import static net.pterodactylus.sone.main.SonePlugin.VERSION;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
private final EventBus eventBus = mock(EventBus.class);
private final FreenetInterface freenetInterface = mock(FreenetInterface.class);
- private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface);
+ private final Version currentVersion = new Version(1, 0, 0);
+ private final UpdateChecker updateChecker = new UpdateChecker(eventBus, freenetInterface, currentVersion);
@Before
public void startUpdateChecker() {
@Test
public void newUpdateCheckerDoesNotHaveALatestVersion() {
assertThat(updateChecker.hasLatestVersion(), is(false));
- assertThat(updateChecker.getLatestVersion(), is(VERSION));
+ assertThat(updateChecker.getLatestVersion(), is(currentVersion));
}
@Test
setupFetchResult(createFutureFetchResult());
setupCallbackWithEdition(MAX_VALUE, true, false);
verifyAFreenetUriIsFetched();
- ArgumentCaptor<UpdateFoundEvent> updateFoundEvent = forClass(UpdateFoundEvent.class);
- verify(eventBus, times(1)).post(updateFoundEvent.capture());
- assertThat(updateFoundEvent.getValue().version(), is(new Version(99, 0, 0)));
- assertThat(updateFoundEvent.getValue().releaseTime(), is(11865368297000L));
- assertThat(updateChecker.getLatestVersion(), is(new Version(99, 0, 0)));
- assertThat(updateChecker.getLatestVersionDate(), is(11865368297000L));
- assertThat(updateChecker.hasLatestVersion(), is(true));
+ verifyEventIsFired(new Version(99, 0, 0), 11865368297000L, false);
+ verifyThatUpdateCheckerKnowsLatestVersion(new Version(99, 0, 0), 11865368297000L);
}
private FetchResult createFutureFetchResult() {
ClientMetadata clientMetadata = new ClientMetadata("application/xml");
Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
"CurrentVersion/Version: 99.0.0\n" +
- "CurrentVersion/ReleaseTime: 11865368297000").getBytes());
+ "CurrentVersion/ReleaseTime: 11865368297000\n" +
+ "DisruptiveVersion/0.1.2: true").getBytes());
return new FetchResult(clientMetadata, fetched);
}
+ private void verifyEventIsFired(Version version, long releaseTime, boolean disruptive) {
+ ArgumentCaptor<UpdateFoundEvent> updateFoundEvent = forClass(UpdateFoundEvent.class);
+ verify(eventBus, times(1)).post(updateFoundEvent.capture());
+ assertThat(updateFoundEvent.getValue().version(), is(version));
+ assertThat(updateFoundEvent.getValue().releaseTime(), is(releaseTime));
+ assertThat(updateFoundEvent.getValue().disruptive(), is(disruptive));
+ }
+
+ private void verifyThatUpdateCheckerKnowsLatestVersion(Version version, long releaseTime) {
+ assertThat(updateChecker.getLatestVersion(), is(version));
+ assertThat(updateChecker.getLatestVersionDate(), is(releaseTime));
+ assertThat(updateChecker.hasLatestVersion(), is(true));
+ }
+
@Test
public void callbackDoesNotStartIfNoNewEditionIsFound() {
setupFetchResult(createPastFetchResult());
return new FetchResult(clientMetadata, fetched);
}
+ @Test
+ public void disruptiveVersionGetsNotification() {
+ setupFetchResult(createDisruptiveVersionFetchResult());
+ setupCallbackWithEdition(MAX_VALUE, true, false);
+ verifyAFreenetUriIsFetched();
+ verifyEventIsFired(new Version(1, 2, 3), 1289417883000L, true);
+ verifyThatUpdateCheckerKnowsLatestVersion(new Version(1, 2, 3), 1289417883000L);
+ }
+
+ private FetchResult createDisruptiveVersionFetchResult() {
+ ClientMetadata clientMetadata = new ClientMetadata("application/xml");
+ Bucket fetched = new ArrayBucket(("# MapConfigurationBackendVersion=1\n" +
+ "CurrentVersion/Version: 1.2.3\n" +
+ "CurrentVersion/ReleaseTime: 1289417883000\n" +
+ "DisruptiveVersion/1.2.3: true").getBytes());
+ return new FetchResult(clientMetadata, fetched);
+ }
+
}
/*
- * Sone - MemoryDatabaseTest.java - Copyright © 2013–2015 David Roden
+ * Sone - MemoryDatabaseTest.java - Copyright © 2013–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
.update();
Album secondAlbum = new TestAlbumBuilder().withId("album2").by(
sone).build().modify().setTitle("album2").setDescription(
- "album-description2").setAlbumImage("image1").update();
+ "album-description2").update();
Album thirdAlbum = new TestAlbumBuilder().withId("album3").by(
sone).build().modify().setTitle("album3").setDescription(
"album-description3").update();
assertThat(memoryDatabase.getPostReply("reply4").isPresent(),
is(false));
assertThat(memoryDatabase.getAlbum("album1").get(),
- isAlbum("album1", null, "album1", "album-description1",
- null));
+ isAlbum("album1", null, "album1", "album-description1"));
assertThat(memoryDatabase.getAlbum("album2").get(),
- isAlbum("album2", null, "album2", "album-description2",
- "image1"));
+ isAlbum("album2", null, "album2", "album-description2"));
assertThat(memoryDatabase.getAlbum("album3").get(),
- isAlbum("album3", "album1", "album3", "album-description3",
- null));
+ isAlbum("album3", "album1", "album3", "album-description3"));
assertThat(memoryDatabase.getAlbum("album4").isPresent(), is(false));
assertThat(memoryDatabase.getImage("image1").get(),
isImage("image1", 1000L, "KSK@image1", "image1",
/*
- * Sone - LockSoneCommandTest.java - Copyright © 2013–2015 David Roden
+ * Sone - LockSoneCommandTest.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
/*
- * Sone - UnlockSoneCommandTest.java - Copyright © 2013–2015 David Roden
+ * Sone - UnlockSoneCommandTest.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
/*
- * Sone - DefaultIdentityTest.java - Copyright © 2013–2015 David Roden
+ * Sone - DefaultIdentityTest.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
/*
- * Sone - DefaultOwnIdentityTest.java - Copyright © 2013–2015 David Roden
+ * Sone - DefaultOwnIdentityTest.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
/*
- * Sone - Identities.java - Copyright © 2013–2015 David Roden
+ * Sone - Identities.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
/*
- * Sone - IdentityChangeDetectorTest.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityChangeDetectorTest.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
/*
- * Sone - IdentityChangeEventSenderTest.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityChangeEventSenderTest.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
/*
- * Sone - IdentityLoaderTest.java - Copyright © 2013–2015 David Roden
+ * Sone - IdentityLoaderTest.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
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.emptyIterable;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.data.SoneOptions;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.util.notify.Notification;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link ListNotificationFilterTest}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ListNotificationFilterTest {
+
+ private static final String LOCAL_ID = "local-id";
+
+ private final PostVisibilityFilter postVisibilityFilter = mock(PostVisibilityFilter.class);
+ private final ReplyVisibilityFilter replyVisibilityFilter = mock(ReplyVisibilityFilter.class);
+ private final ListNotificationFilter listNotificationFilter = new ListNotificationFilter(postVisibilityFilter, replyVisibilityFilter);
+
+ private final Sone localSone = mock(Sone.class);
+ private final SoneOptions soneOptions = mock(SoneOptions.class);
+ private final OwnIdentity localIdentity = mock(OwnIdentity.class);
+ private final List<ListNotification<Post>> newPostNotifications = Arrays.asList(createNewPostNotification());
+ private final List<ListNotification<PostReply>> newReplyNotifications = Arrays.asList(createNewReplyNotification());
+ private final List<ListNotification<Post>> mentionNotifications = Arrays.asList(createMentionNotification());
+
+ public ListNotificationFilterTest() {
+ when(localSone.getId()).thenReturn(LOCAL_ID);
+ when(localSone.isLocal()).thenReturn(true);
+ when(localSone.getIdentity()).thenReturn(localIdentity);
+ when(localIdentity.getId()).thenReturn(LOCAL_ID);
+ when(localSone.getOptions()).thenReturn(soneOptions);
+ }
+
+ @Test
+ public void filterIsOnlyCreatedOnce() {
+ Injector injector = Guice.createInjector();
+ ListNotificationFilter firstFilter = injector.getInstance(ListNotificationFilter.class);
+ ListNotificationFilter secondFilter = injector.getInstance(ListNotificationFilter.class);
+ assertThat(firstFilter, sameInstance(secondFilter));
+ }
+
+ @Test
+ public void newSoneNotificationsAreNotRemovedIfNotLoggedIn() {
+ List<Notification> notifications = Arrays.asList(createNewSoneNotification());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(notifications, null);
+ assertThat(filteredNotifications, contains(notifications.get(0)));
+ }
+
+ private Notification createNewSoneNotification() {
+ ListNotification<Sone> newSoneNotification = mock(ListNotification.class);
+ when(newSoneNotification.getId()).thenReturn("new-sone-notification");
+ return newSoneNotification;
+ }
+
+ @Test
+ public void newSoneNotificationsAreRemovedIfLoggedInAndNewSonesShouldNotBeShown() {
+ List<Notification> notifications = Arrays.asList(createNewSoneNotification());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(notifications, localSone);
+ assertThat(filteredNotifications, emptyIterable());
+ }
+
+ @Test
+ public void newSoneNotificationsAreNotRemovedIfLoggedInAndNewSonesShouldBeShown() {
+ List<Notification> notifications = Arrays.asList(createNewSoneNotification());
+ when(soneOptions.isShowNewSoneNotifications()).thenReturn(true);
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(notifications, localSone);
+ assertThat(filteredNotifications, contains(notifications.get(0)));
+ }
+
+ private ListNotification<Post> createNewPostNotification() {
+ ListNotification<Post> newSoneNotification = mock(ListNotification.class);
+ when(newSoneNotification.getElements()).thenReturn(new ArrayList<Post>());
+ when(newSoneNotification.getId()).thenReturn("new-post-notification");
+ return newSoneNotification;
+ }
+
+ @Test
+ public void newPostNotificationIsNotShownIfOptionsSetAccordingly() {
+ List<ListNotification<Post>> notifications = Arrays.asList(createNewPostNotification());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(notifications, localSone);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ private void activateNewPostNotifications() {
+ when(soneOptions.isShowNewPostNotifications()).thenReturn(true);
+ }
+
+ private boolean addPostToPostNotification(List<ListNotification<Post>> notifications) {
+ return notifications.get(0).getElements().add(mock(Post.class));
+ }
+
+ private void setPostVisibilityPredicate(Predicate<Post> value) {
+ when(postVisibilityFilter.isVisible(any(Sone.class))).thenReturn(value);
+ }
+
+ @Test
+ public void newPostNotificationIsNotShownIfNoNewPostsAreVisible() {
+ activateNewPostNotifications();
+ addPostToPostNotification(newPostNotifications);
+ setPostVisibilityPredicate(Predicates.<Post>alwaysFalse());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newPostNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ @Test
+ public void newPostNotificationIsShownIfNewPostsAreVisible() {
+ activateNewPostNotifications();
+ addPostToPostNotification(newPostNotifications);
+ setPostVisibilityPredicate(Predicates.<Post>alwaysTrue());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newPostNotifications, localSone);
+ assertThat(filteredNotifications, contains((Notification) newPostNotifications.get(0)));
+ }
+
+ @Test
+ public void newPostNotificationIsNotShownIfNewPostsAreVisibleButLocalSoneIsNull() {
+ activateNewPostNotifications();
+ addPostToPostNotification(newPostNotifications);
+ setPostVisibilityPredicate(Predicates.<Post>alwaysTrue());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newPostNotifications, null);
+ assertThat(filteredNotifications, Matchers.<Notification>emptyIterable());
+ }
+
+ @Test
+ public void newPostNotificationContainsOnlyVisiblePosts() {
+ activateNewPostNotifications();
+ addPostToPostNotification(newPostNotifications);
+ addPostToPostNotification(newPostNotifications);
+ setPostVisibilityPredicate(new Predicate<Post>() {
+ @Override
+ public boolean apply(@Nullable Post post) {
+ return post.equals(newPostNotifications.get(0).getElements().get(1));
+ }
+ });
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newPostNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(1));
+ assertThat(((ListNotification<Post>) filteredNotifications.get(0)).getElements().get(0), is(newPostNotifications.get(0).getElements().get(1)));
+ }
+
+ private ListNotification<PostReply> createNewReplyNotification() {
+ ListNotification<PostReply> newReplyNotifications = mock(ListNotification.class);
+ when(newReplyNotifications.getElements()).thenReturn(new ArrayList<PostReply>());
+ when(newReplyNotifications.getId()).thenReturn("new-reply-notification");
+ return newReplyNotifications;
+ }
+
+ private void activateNewReplyNotifications() {
+ when(soneOptions.isShowNewReplyNotifications()).thenReturn(true);
+ }
+
+ private void addReplyToNewReplyNotification(List<ListNotification<PostReply>> notifications) {
+ notifications.get(0).getElements().add(mock(PostReply.class));
+ }
+
+ private void setReplyVisibilityPredicate(Predicate<PostReply> value) {
+ when(replyVisibilityFilter.isVisible(any(Sone.class))).thenReturn(value);
+ }
+
+ @Test
+ public void newReplyNotificationContainsOnlyVisibleReplies() {
+ activateNewReplyNotifications();
+ addReplyToNewReplyNotification(newReplyNotifications);
+ addReplyToNewReplyNotification(newReplyNotifications);
+ setReplyVisibilityPredicate(new Predicate<PostReply>() {
+ @Override
+ public boolean apply(@Nullable PostReply postReply) {
+ return postReply.equals(newReplyNotifications.get(0).getElements().get(1));
+ }
+ });
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newReplyNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(1));
+ assertThat(((ListNotification<PostReply>) filteredNotifications.get(0)).getElements().get(0), is(newReplyNotifications.get(0).getElements().get(1)));
+ }
+
+ @Test
+ public void newReplyNotificationIsNotModifiedIfAllRepliesAreVisible() {
+ activateNewReplyNotifications();
+ addReplyToNewReplyNotification(newReplyNotifications);
+ addReplyToNewReplyNotification(newReplyNotifications);
+ setReplyVisibilityPredicate(Predicates.<PostReply>alwaysTrue());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newReplyNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(1));
+ assertThat(filteredNotifications.get(0), is((Notification) newReplyNotifications.get(0)));
+ assertThat(((ListNotification<PostReply>) filteredNotifications.get(0)).getElements(), hasSize(2));
+ }
+
+ @Test
+ public void newReplyNotificationIsNotShownIfNoRepliesAreVisible() {
+ activateNewReplyNotifications();
+ addReplyToNewReplyNotification(newReplyNotifications);
+ addReplyToNewReplyNotification(newReplyNotifications);
+ setReplyVisibilityPredicate(Predicates.<PostReply>alwaysFalse());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newReplyNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ @Test
+ public void newReplyNotificationIsNotShownIfDeactivatedInOptions() {
+ addReplyToNewReplyNotification(newReplyNotifications);
+ addReplyToNewReplyNotification(newReplyNotifications);
+ setReplyVisibilityPredicate(Predicates.<PostReply>alwaysTrue());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newReplyNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ @Test
+ public void newReplyNotificationIsNotShownIfCurrentSoneIsNull() {
+ addReplyToNewReplyNotification(newReplyNotifications);
+ addReplyToNewReplyNotification(newReplyNotifications);
+ setReplyVisibilityPredicate(Predicates.<PostReply>alwaysTrue());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(newReplyNotifications, null);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ private ListNotification<Post> createMentionNotification() {
+ ListNotification<Post> newSoneNotification = mock(ListNotification.class);
+ when(newSoneNotification.getElements()).thenReturn(new ArrayList<Post>());
+ when(newSoneNotification.getId()).thenReturn("mention-notification");
+ return newSoneNotification;
+ }
+
+ @Test
+ public void mentionNotificationContainsOnlyVisiblePosts() {
+ addPostToPostNotification(mentionNotifications);
+ addPostToPostNotification(mentionNotifications);
+ setPostVisibilityPredicate(new Predicate<Post>() {
+ @Override
+ public boolean apply(@Nullable Post post) {
+ return post.equals(mentionNotifications.get(0).getElements().get(1));
+ }
+ });
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(mentionNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(1));
+ assertThat(((ListNotification<Post>) filteredNotifications.get(0)).getElements().get(0), is(mentionNotifications.get(0).getElements().get(1)));
+ }
+
+ @Test
+ public void mentionNotificationIsNotShownIfNoPostsAreVisible() {
+ addPostToPostNotification(mentionNotifications);
+ addPostToPostNotification(mentionNotifications);
+ setPostVisibilityPredicate(Predicates.<Post>alwaysFalse());
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(mentionNotifications, localSone);
+ assertThat(filteredNotifications, hasSize(0));
+ }
+
+ @Test
+ public void unfilterableNotificationIsNotFiltered() {
+ Notification notification = mock(Notification.class);
+ when(notification.getId()).thenReturn("random-notification");
+ List<Notification> notifications = Arrays.asList(notification);
+ List<Notification> filteredNotifications = listNotificationFilter.filterNotifications(notifications, null);
+ assertThat(filteredNotifications, contains(notification));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.emptyIterable;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+
+import net.pterodactylus.util.notify.NotificationListener;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link ListNotification}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ListNotificationTest {
+
+ private static final String ID = "notification-id";
+ private static final String KEY = "element-key";
+ private static final String OTHER_KEY = "other-key";
+
+ private final Template template = mock(Template.class);
+ private final TemplateContext templateInitialContext = mock(TemplateContext.class);
+ private ListNotification<Object> listNotification;
+
+ public ListNotificationTest() {
+ when(template.getInitialContext()).thenReturn(templateInitialContext);
+ listNotification = new ListNotification<Object>(ID, KEY, template);
+ }
+
+ @Test
+ public void creatingAListNotificationSetsEmptyIterableOnElementKeyInTemplateContext() {
+ verify(templateInitialContext).set(eq(KEY), argThat(emptyIterable()));
+ }
+
+ @Test
+ public void newListNotificationHasNoElement() {
+ assertThat(listNotification.getElements(), emptyIterable());
+ }
+
+ @Test
+ public void newListNotificationIsEmpty() {
+ assertThat(listNotification.isEmpty(), is(true));
+ }
+
+ @Test
+ public void listNotificationRetainsSetElements() {
+ listNotification.setElements(Arrays.asList("a", "b", "c"));
+ assertThat(listNotification.getElements(), Matchers.<Object>contains("a", "b", "c"));
+ }
+
+ @Test
+ public void listNotificationRetainsAddedElements() {
+ listNotification.add("a");
+ listNotification.add("b");
+ listNotification.add("c");
+ assertThat(listNotification.getElements(), Matchers.<Object>contains("a", "b", "c"));
+ }
+
+ @Test
+ public void listNotificationRemovesCorrectElement() {
+ listNotification.setElements(Arrays.asList("a", "b", "c"));
+ listNotification.remove("b");
+ assertThat(listNotification.getElements(), Matchers.<Object>contains("a", "c"));
+ }
+
+ @Test
+ public void removingTheLastElementDismissesTheNotification() {
+ NotificationListener notificationListener = mock(NotificationListener.class);
+ listNotification.addNotificationListener(notificationListener);
+ listNotification.add("a");
+ listNotification.remove("a");
+ verify(notificationListener).notificationDismissed(listNotification);
+ }
+
+ @Test
+ public void dismissingTheListNotificationRemovesAllElements() {
+ listNotification.setElements(Arrays.asList("a", "b", "c"));
+ listNotification.dismiss();
+ assertThat(listNotification.getElements(), emptyIterable());
+ }
+
+ @Test
+ public void listNotificationWithDifferentElementsIsNotEqual() {
+ ListNotification secondNotification = new ListNotification(ID, KEY, template);
+ listNotification.add("a");
+ secondNotification.add("b");
+ assertThat(listNotification, not(is(secondNotification)));
+ }
+
+ @Test
+ public void listNotificationWithDifferentKeyIsNotEqual() {
+ ListNotification secondNotification = new ListNotification(ID, OTHER_KEY, template);
+ assertThat(listNotification, not(is(secondNotification)));
+ }
+
+ @Test
+ public void copiedNotificationsHaveTheSameHashCode() {
+ ListNotification secondNotification = new ListNotification(listNotification);
+ listNotification.add("a");
+ secondNotification.add("a");
+ assertThat(listNotification.hashCode(), is(secondNotification.hashCode()));
+ }
+
+ @Test
+ public void listNotificationIsNotEqualToOtherObjects() {
+ assertThat(listNotification, not(is(new Object())));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.sone.freenet.wot.Trust;
+
+import com.google.common.base.Optional;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link PostVisibilityFilterTest}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostVisibilityFilterTest {
+
+ private static final String LOCAL_ID = "local-id";
+ private static final String REMOTE_ID = "remote-id";
+
+ private final PostVisibilityFilter postVisibilityFilter = new PostVisibilityFilter();
+
+ private final Sone localSone = mock(Sone.class);
+ private final OwnIdentity localIdentity = mock(OwnIdentity.class);
+ private final Post post = mock(Post.class);
+ private final Sone remoteSone = mock(Sone.class);
+ private final Identity remoteIdentity = mock(Identity.class);
+
+ public PostVisibilityFilterTest() {
+ when(localSone.getId()).thenReturn(LOCAL_ID);
+ when(localSone.isLocal()).thenReturn(true);
+ when(localSone.getIdentity()).thenReturn(localIdentity);
+ when(localIdentity.getId()).thenReturn(LOCAL_ID);
+ when(remoteSone.getId()).thenReturn(REMOTE_ID);
+ when(remoteSone.getIdentity()).thenReturn(remoteIdentity);
+ when(remoteIdentity.getId()).thenReturn(REMOTE_ID);
+ when(post.getRecipientId()).thenReturn(Optional.<String>absent());
+ }
+
+ @Test
+ public void postVisibilityFilterIsOnlyCreatedOnce() {
+ Injector injector = Guice.createInjector();
+ PostVisibilityFilter firstFilter = injector.getInstance(PostVisibilityFilter.class);
+ PostVisibilityFilter secondFilter = injector.getInstance(PostVisibilityFilter.class);
+ assertThat(firstFilter, sameInstance(secondFilter));
+ }
+
+ @Test
+ public void postIsNotVisibleIfItIsNotLoaded() {
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(false));
+ }
+
+ private static void makePostLoaded(Post post) {
+ when(post.isLoaded()).thenReturn(true);
+ }
+
+ @Test
+ public void loadedPostIsVisibleWithoutSone() {
+ makePostLoaded(post);
+ assertThat(postVisibilityFilter.isPostVisible(null, post), is(true));
+ }
+
+ private void makePostComeFromTheFuture() {
+ when(post.getTime()).thenReturn(System.currentTimeMillis() + 1000);
+ }
+
+ @Test
+ public void loadedPostFromTheFutureIsNotVisible() {
+ makePostLoaded(post);
+ makePostComeFromTheFuture();
+ assertThat(postVisibilityFilter.isPostVisible(null, post), is(false));
+ }
+
+ private void makePostFromRemoteSone() {
+ when(post.getSone()).thenReturn(remoteSone);
+ }
+
+ private void giveRemoteIdentityNegativeExplicitTrust() {
+ when(remoteIdentity.getTrust(localIdentity)).thenReturn(new Trust(-1, null, null));
+ }
+
+ @Test
+ public void loadedPostFromExplicitelyNotTrustedSoneIsNotVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ giveRemoteIdentityNegativeExplicitTrust();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(false));
+ }
+
+ private void giveRemoteIdentityNegativeImplicitTrust() {
+ when(remoteIdentity.getTrust(localIdentity)).thenReturn(new Trust(null, -1, null));
+ }
+
+ @Test
+ public void loadedPostFromImplicitelyUntrustedSoneIsNotVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ giveRemoteIdentityNegativeImplicitTrust();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(false));
+ }
+
+ private void makeLocalSoneFollowRemoteSone() {
+ when(localSone.hasFriend(REMOTE_ID)).thenReturn(true);
+ }
+
+ private void giveRemoteIdentityPositiveExplicitTrustButNegativeImplicitTrust() {
+ when(remoteIdentity.getTrust(localIdentity)).thenReturn(new Trust(1, -1, null));
+ }
+
+ @Test
+ public void loadedPostFromExplicitelyTrustedButImplicitelyUntrustedSoneIsVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ makeLocalSoneFollowRemoteSone();
+ giveRemoteIdentityPositiveExplicitTrustButNegativeImplicitTrust();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ private void giveTheRemoteIdentityPositiveImplicitTrust() {
+ when(remoteIdentity.getTrust(localIdentity)).thenReturn(new Trust(null, 1, null));
+ }
+
+ @Test
+ public void loadedPostFromImplicitelyTrustedSoneIsVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ makeLocalSoneFollowRemoteSone();
+ giveTheRemoteIdentityPositiveImplicitTrust();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ private void giveTheRemoteIdentityUnknownTrust() {
+ when(remoteIdentity.getTrust(localIdentity)).thenReturn(new Trust(null, null, null));
+ }
+
+ @Test
+ public void loadedPostFromSoneWithUnknownTrustIsVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ makeLocalSoneFollowRemoteSone();
+ giveTheRemoteIdentityUnknownTrust();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ @Test
+ public void loadedPostFromUnfollowedRemoteSoneThatIsNotDirectedAtLocalSoneIsNotVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(false));
+ }
+
+ private void makePostFromLocalSone() {
+ makePostLoaded(post);
+ when(post.getSone()).thenReturn(localSone);
+ }
+
+ @Test
+ public void loadedPostFromLocalSoneIsVisible() {
+ makePostFromLocalSone();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ @Test
+ public void loadedPostFromFollowedRemoteSoneThatIsNotDirectedAtLocalSoneIsVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ makeLocalSoneFollowRemoteSone();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ private void makePostDirectedAtLocalId() {
+ when(post.getRecipientId()).thenReturn(Optional.of(LOCAL_ID));
+ }
+
+ @Test
+ public void loadedPostFromRemoteSoneThatIsDirectedAtLocalSoneIsVisible() {
+ makePostLoaded(post);
+ makePostFromRemoteSone();
+ makePostDirectedAtLocalId();
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), is(true));
+ }
+
+ @Test
+ public void predicateWillCorrectlyRecognizeVisiblePost() {
+ makePostFromLocalSone();
+ assertThat(postVisibilityFilter.isVisible(null).apply(post), is(true));
+ }
+
+ @Test
+ public void predicateWillCorrectlyRecognizeNotVisiblePost() {
+ assertThat(postVisibilityFilter.isVisible(null).apply(post), is(false));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+
+import com.google.common.base.Optional;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link ReplyVisibilityFilterTest}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ReplyVisibilityFilterTest {
+
+ private static final String LOCAL_ID = "local-id";
+
+ private final PostVisibilityFilter postVisibilityFilter = mock(PostVisibilityFilter.class);
+ private final ReplyVisibilityFilter replyVisibilityFilter = new ReplyVisibilityFilter(postVisibilityFilter);
+
+ private final Sone localSone = mock(Sone.class);
+ private final OwnIdentity localIdentity = mock(OwnIdentity.class);
+ private final Post post = mock(Post.class);
+ private final PostReply postReply = mock(PostReply.class);
+
+ public ReplyVisibilityFilterTest() {
+ when(localSone.getId()).thenReturn(LOCAL_ID);
+ when(localSone.isLocal()).thenReturn(true);
+ when(localSone.getIdentity()).thenReturn(localIdentity);
+ when(post.getRecipientId()).thenReturn(Optional.<String>absent());
+ }
+
+ @Test
+ public void replyVisibilityFilterIsOnlyCreatedOnce() {
+ Injector injector = Guice.createInjector();
+ ReplyVisibilityFilter firstFilter = injector.getInstance(ReplyVisibilityFilter.class);
+ ReplyVisibilityFilter secondFilter = injector.getInstance(ReplyVisibilityFilter.class);
+ assertThat(firstFilter, sameInstance(secondFilter));
+ }
+
+ private void makePostPresent() {
+ when(postReply.getPost()).thenReturn(Optional.of(post));
+ }
+
+ @Test
+ public void replyIsNotVisibleIfPostIsNotVisible() {
+ makePostPresent();
+ assertThat(replyVisibilityFilter.isReplyVisible(localSone, postReply), is(false));
+ }
+
+ private void makePostAbsent() {
+ when(postReply.getPost()).thenReturn(Optional.<Post>absent());
+ }
+
+ @Test
+ public void replyIsNotVisibleIfPostIsNotPresent() {
+ makePostAbsent();
+ assertThat(replyVisibilityFilter.isReplyVisible(localSone, postReply), is(false));
+ }
+
+ private void makePostPresentAndVisible() {
+ makePostPresent();
+ when(postVisibilityFilter.isPostVisible(localSone, post)).thenReturn(true);
+ }
+
+ private void makeReplyComeFromFuture() {
+ when(postReply.getTime()).thenReturn(System.currentTimeMillis() + 1000);
+ }
+
+ @Test
+ public void replyIsNotVisibleIfItIsFromTheFuture() {
+ makePostPresentAndVisible();
+ makeReplyComeFromFuture();
+ assertThat(replyVisibilityFilter.isReplyVisible(localSone, postReply), is(false));
+ }
+
+ @Test
+ public void replyIsVisibleIfItIsNotFromTheFuture() {
+ makePostPresentAndVisible();
+ assertThat(replyVisibilityFilter.isReplyVisible(localSone, postReply), is(true));
+ }
+
+ @Test
+ public void predicateCorrectlyRecognizesVisibleReply() {
+ makePostPresentAndVisible();
+ assertThat(replyVisibilityFilter.isVisible(localSone).apply(postReply), is(true));
+ }
+
+ @Test
+ public void predicateCorrectlyRecognizesNotVisibleReply() {
+ makePostPresentAndVisible();
+ makeReplyComeFromFuture();
+ assertThat(replyVisibilityFilter.isVisible(localSone).apply(postReply), is(false));
+ }
+
+}
package net.pterodactylus.sone.template;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import net.pterodactylus.sone.TestUtil;
import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
};
}
+ @Test
+ public void albumImageIsGeneratedRandomly() {
+ Image image = mock(Image.class);
+ List<Image> albumImages = Arrays.asList(mock(Image.class), image);
+ when(album.getImages()).thenReturn(albumImages);
+ int matchedImage = 0;
+ for (int i = 0; i < 1000; i++) {
+ Image randomImage = (Image) albumAccessor.get(null, album, "albumImage");
+ if (randomImage == image) {
+ matchedImage++;
+ }
+ }
+ assertThat(matchedImage, allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(750)));
+ }
+
+ @Test
+ public void albumImageIsNullIfThereAreNoImagesInAnAlbum() {
+ when(album.getImages()).thenReturn(Collections.<Image>emptyList());
+ assertThat(albumAccessor.get(null, album, "albumImage"), nullValue());
+ }
+
}
--- /dev/null
+package net.pterodactylus.sone.template;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import net.pterodactylus.util.number.Hex;
+
+import org.junit.Test;
+
+/**
+ * Unit test for {@link JavascriptFilter}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class JavascriptFilterTest {
+
+ private final JavascriptFilter filter = new JavascriptFilter();
+
+ @Test
+ public void filterEscapesAllCharactersBelowSpace() {
+ String source = buildStringWithAllCharactersToEscape();
+ String target = buildStringWithEscapedCharacters();
+ assertThat((String) filter.format(null, source, null), is("\"" + target + "\""));
+ }
+
+ private String buildStringWithAllCharactersToEscape() {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < 32; i++) {
+ stringBuilder.append((char) i);
+ }
+ stringBuilder.append('"').append("\\").append("!");
+ return stringBuilder.toString();
+ }
+
+ private String buildStringWithEscapedCharacters() {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < 32; i++) {
+ switch (i) {
+ case 9:
+ stringBuilder.append("\\t");
+ break;
+ case 10:
+ stringBuilder.append("\\n");
+ break;
+ case 13:
+ stringBuilder.append("\\r");
+ break;
+ default:
+ stringBuilder.append("\\x").append(Hex.toHex(i, 2));
+ }
+ }
+ stringBuilder.append("\\\"").append("\\\\").append("!");
+ return stringBuilder.toString();
+ }
+
+}
/*
- * Sone - SoneTextParserTest.java - Copyright © 2011–2015 David Roden
+ * Sone - SoneTextParserTest.java - Copyright © 2011–2016 David Roden
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
package net.pterodactylus.sone.text;
import java.io.IOException;
-import java.io.StringReader;
import java.util.Arrays;
import java.util.Collection;
Iterable<Part> parts;
/* check basic operation. */
- parts = soneTextParser.parse(null, new StringReader("Test."));
+ parts = soneTextParser.parse("Test.", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Test.", convertText(parts, PlainTextPart.class));
/* check empty lines at start and end. */
- parts = soneTextParser.parse(null, new StringReader("\nTest.\n\n"));
+ parts = soneTextParser.parse("\nTest.\n\n", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Test.", convertText(parts, PlainTextPart.class));
/* check duplicate empty lines in the text. */
- parts = soneTextParser.parse(null, new StringReader("\nTest.\n\n\nTest."));
+ parts = soneTextParser.parse("\nTest.\n\n\nTest.", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Test.\n\nTest.", convertText(parts, PlainTextPart.class));
}
Iterable<Part> parts;
/* check basic links. */
- parts = soneTextParser.parse(null, new StringReader("KSK@gpl.txt"));
+ parts = soneTextParser.parse("KSK@gpl.txt", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "[KSK@gpl.txt|gpl.txt|gpl.txt]", convertText(parts, FreenetLinkPart.class));
/* check embedded links. */
- parts = soneTextParser.parse(null, new StringReader("Link is KSK@gpl.txt\u200b."));
+ parts = soneTextParser.parse("Link is KSK@gpl.txt\u200b.", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\u200b.", convertText(parts, PlainTextPart.class, FreenetLinkPart.class));
/* check embedded links and line breaks. */
- parts = soneTextParser.parse(null, new StringReader("Link is KSK@gpl.txt\nKSK@test.dat\n"));
+ parts = soneTextParser.parse("Link is KSK@gpl.txt\nKSK@test.dat\n", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Link is [KSK@gpl.txt|gpl.txt|gpl.txt]\n[KSK@test.dat|test.dat|test.dat]", convertText(parts, PlainTextPart.class, FreenetLinkPart.class));
}
Iterable<Part> parts;
/* check basic links. */
- parts = soneTextParser.parse(null, new StringReader("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff."));
+ parts = soneTextParser.parse("Some text.\n\nLink to sone://DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU and stuff.", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff.", convertText(parts, PlainTextPart.class, SonePart.class));
}
Iterable<Part> parts;
/* check empty http links. */
- parts = soneTextParser.parse(null, new StringReader("Some text. Empty link: http:// – nice!"));
+ parts = soneTextParser.parse("Some text. Empty link: http:// – nice!", null);
assertNotNull("Parts", parts);
assertEquals("Part Text", "Some text. Empty link: http:// – nice!", convertText(parts, PlainTextPart.class));
}
--- /dev/null
+package net.pterodactylus.sone.web;
+
+import static net.pterodactylus.sone.web.WebTestUtils.redirectsTo;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.notify.Notification;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.web.Method;
+
+import freenet.support.api.HTTPRequest;
+
+import com.google.common.base.Optional;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Matchers;
+
+/**
+ * Unit test for {@link DeleteReplyPage}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class DeleteReplyPageTest {
+
+ @Rule
+ public final ExpectedException expectedException = ExpectedException.none();
+
+ private final Template template = new Template();
+ private final WebInterface webInterface = mock(WebInterface.class, RETURNS_DEEP_STUBS);
+ private final DeleteReplyPage page = new DeleteReplyPage(template, webInterface);
+ private final TemplateContext templateContext = new TemplateContext();
+ private final FreenetRequest freenetRequest = mock(FreenetRequest.class);
+ private final HTTPRequest httpRequest = mock(HTTPRequest.class);
+
+ @Before
+ public void setupWebInterface() {
+ when(webInterface.getNotifications(Matchers.any(Sone.class))).thenReturn(Collections.<Notification>emptyList());
+ }
+
+ @Before
+ public void setupHttpRequest() {
+ when(freenetRequest.getHttpRequest()).thenReturn(httpRequest);
+ }
+
+ @Test
+ public void tryingToDeleteAReplyWithAnInvalidIdResultsInNoPermissionPage() throws Exception {
+ when(freenetRequest.getMethod()).thenReturn(Method.POST);
+ when(httpRequest.getPartAsStringFailsafe(eq("reply"), anyInt())).thenReturn("id");
+ when(webInterface.getCore().getPostReply("id")).thenReturn(Optional.<PostReply>absent());
+ expectedException.expect(redirectsTo("noPermission.html"));
+ page.processTemplate(freenetRequest, templateContext);
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.web;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.notify.Notification;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+import freenet.clients.http.ToadletContext;
+
+import com.google.common.base.Optional;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit test for {@link NewPage}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class NewPageTest {
+
+ private final Template template = mock(Template.class);
+ private final WebInterface webInterface = mock(WebInterface.class, RETURNS_DEEP_STUBS);
+ private final NewPage newPage = new NewPage(template, webInterface);
+ private final Sone currentSone = mock(Sone.class);
+ private final TemplateContext templateContext = new TemplateContext();
+ private final FreenetRequest freenetRequest = mock(FreenetRequest.class, RETURNS_DEEP_STUBS);
+
+ @Before
+ public void setupFreenetRequest() {
+ when(freenetRequest.getToadletContext()).thenReturn(mock(ToadletContext.class));
+ }
+
+ @Before
+ public void setupWebInterface() {
+ when(webInterface.getCore().getPreferences().getPostsPerPage()).thenReturn(5);
+ when(webInterface.getCurrentSone(any(ToadletContext.class), anyBoolean())).thenReturn(currentSone);
+ when(webInterface.getNotifications(any(Sone.class))).thenReturn(Collections.<Notification>emptyList());
+ }
+
+ @Test
+ public void postsAreNotDuplicatedWhenTheyComeFromBothNewPostsAndNewRepliesNotifications() throws Exception {
+ // given
+ Post extraPost = mock(Post.class);
+ List<Post> posts = asList(mock(Post.class), mock(Post.class));
+ List<PostReply> postReplies = asList(mock(PostReply.class), mock(PostReply.class));
+ when(postReplies.get(0).getPost()).thenReturn(Optional.of(posts.get(0)));
+ when(postReplies.get(1).getPost()).thenReturn(Optional.of(extraPost));
+ when(webInterface.getNewPosts(currentSone)).thenReturn(posts);
+ when(webInterface.getNewReplies(currentSone)).thenReturn(postReplies);
+
+ // when
+ newPage.processTemplate(freenetRequest, templateContext);
+
+ // then
+ List<Post> renderedPosts = templateContext.get("posts", List.class);
+ assertThat(renderedPosts, containsInAnyOrder(posts.get(0), posts.get(1), extraPost));
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.web;
+
+import static net.pterodactylus.sone.web.WebTestUtils.redirectsTo;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+
+import net.pterodactylus.sone.core.Core;
+import net.pterodactylus.sone.core.UpdateChecker;
+import net.pterodactylus.sone.data.Album;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.web.Method;
+
+import freenet.clients.http.ToadletContext;
+import freenet.support.api.HTTPRequest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+/**
+ * Unit test for {@link UploadImagePageTest}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class UploadImagePageTest {
+
+ @Rule
+ public final ExpectedException expectedException = ExpectedException.none();
+
+ private final Template template = new Template();
+ private final WebInterface webInterface = mock(WebInterface.class);
+ private final UploadImagePage uploadImagePage = new UploadImagePage(template, webInterface);
+
+ private final TemplateContext templateContext = new TemplateContext();
+ private final HTTPRequest httpRequest = mock(HTTPRequest.class);
+ private final ToadletContext toadletContext = mock(ToadletContext.class);
+ private final Core core = mock(Core.class);
+ private final Sone currentSone = mock(Sone.class);
+ private final Album parentAlbum = mock(Album.class);
+
+ @Before
+ public void setupWebInterface() {
+ UpdateChecker updateChecker = mock(UpdateChecker.class);
+ when(core.getUpdateChecker()).thenReturn(updateChecker);
+ when(webInterface.getCore()).thenReturn(core);
+ when(webInterface.getCurrentSone(any(ToadletContext.class))).thenReturn(currentSone);
+ }
+
+ @Before
+ public void setupParentAlbum() {
+ when(core.getAlbum("parent-id")).thenReturn(parentAlbum);
+ when(parentAlbum.getSone()).thenReturn(currentSone);
+ }
+
+ @Test
+ public void uploadingAnImageWithoutTitleRedirectsToEmptyImageTitlePage() throws Exception {
+ FreenetRequest request = new FreenetRequest(new URI(""), Method.POST, httpRequest, toadletContext);
+ when(httpRequest.getPartAsStringFailsafe(eq("parent"), anyInt())).thenReturn("parent-id");
+ when(httpRequest.getPartAsStringFailsafe(eq("title"), anyInt())).thenReturn(" ");
+ expectedException.expect(redirectsTo("emptyImageTitle.html"));
+ uploadImagePage.processTemplate(request, templateContext);
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.web;
+
+import javax.annotation.Nonnull;
+
+import net.pterodactylus.sone.web.page.FreenetTemplatePage.RedirectException;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+
+/**
+ * Utilities for testing the <code>web</code> package.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class WebTestUtils {
+
+ @Nonnull
+ public static Matcher<RedirectException> redirectsTo(@Nonnull final String page) {
+ return new TypeSafeDiagnosingMatcher<RedirectException>() {
+ @Override
+ protected boolean matchesSafely(RedirectException exception, Description mismatchDescription) {
+ if (!exception.getTarget().equals(page)) {
+ mismatchDescription.appendText("target is ").appendValue(exception.getTarget());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("target is ").appendValue(page);
+ }
+ };
+ }
+
+}
--- /dev/null
+package net.pterodactylus.sone.web.ajax;
+
+import static java.lang.System.currentTimeMillis;
+import static net.pterodactylus.sone.web.ajax.GetTimesAjaxPage.getTime;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.when;
+
+import net.pterodactylus.sone.web.WebInterface;
+import net.pterodactylus.sone.web.ajax.GetTimesAjaxPage.Time;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Unit test for {@link GetTimesAjaxPage}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class GetTimesAjaxPageTest {
+
+ private final WebInterface webInterface = Mockito.mock(WebInterface.class, RETURNS_DEEP_STUBS);
+
+ @Test
+ public void timestampInTheFutureIsTranslatedCorrectly() {
+ when(webInterface.getL10n().getString("View.Time.InTheFuture")).thenReturn("in the future");
+ Time time = getTime(webInterface, currentTimeMillis() + 100);
+ assertThat(time.getText(), is("in the future"));
+ }
+
+ @Test
+ public void timestampAFewSecondsAgoIsTranslatedCorrectly() {
+ when(webInterface.getL10n().getString("View.Time.AFewSecondsAgo")).thenReturn("a few seconds ago");
+ Time time = getTime(webInterface, currentTimeMillis() - 1000);
+ assertThat(time.getText(), is("a few seconds ago"));
+ }
+
+}