From: David ‘Bombe’ Roden Date: Thu, 13 Jan 2011 20:31:48 +0000 (+0100) Subject: Merge branch 'release-0.3.7' X-Git-Tag: 0.3.7^0 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=fa63b855e28c5fbf270bfdca1bb23fd048affae5;hp=915e48ef36a444907c00e818c8215db172c089a6 Merge branch 'release-0.3.7' --- diff --git a/pom.xml b/pom.xml index e1fe047..eae705c 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 net.pterodactylus sone - 0.3.6-5 + 0.3.7 net.pterodactylus utils - 0.7.6 + 0.7.7 junit diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 493221b..78df9ef 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -45,6 +45,7 @@ import net.pterodactylus.util.config.Configuration; import net.pterodactylus.util.config.ConfigurationException; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.number.Numbers; +import net.pterodactylus.util.version.Version; import freenet.keys.FreenetURI; /** @@ -52,7 +53,7 @@ import freenet.keys.FreenetURI; * * @author David ‘Bombe’ Roden */ -public class Core implements IdentityListener { +public class Core implements IdentityListener, UpdateListener { /** * Enumeration for the possible states of a {@link Sone}. @@ -98,6 +99,9 @@ public class Core implements IdentityListener { /** The Sone downloader. */ private final SoneDownloader soneDownloader; + /** The update checker. */ + private final UpdateChecker updateChecker; + /** Whether the core has been stopped. */ private volatile boolean stopped; @@ -162,6 +166,7 @@ public class Core implements IdentityListener { this.freenetInterface = freenetInterface; this.identityManager = identityManager; this.soneDownloader = new SoneDownloader(this, freenetInterface); + this.updateChecker = new UpdateChecker(freenetInterface); } // @@ -233,6 +238,15 @@ public class Core implements IdentityListener { } /** + * Returns the update checker. + * + * @return The update checker + */ + public UpdateChecker getUpdateChecker() { + return updateChecker; + } + + /** * Returns the status of the given Sone. * * @param sone @@ -1400,6 +1414,8 @@ public class Core implements IdentityListener { */ public void start() { loadConfiguration(); + updateChecker.addUpdateListener(this); + updateChecker.start(); } /** @@ -1411,6 +1427,8 @@ public class Core implements IdentityListener { soneInserter.stop(); } } + updateChecker.stop(); + updateChecker.removeUpdateListener(this); soneDownloader.stop(); saveConfiguration(); stopped = true; @@ -1622,4 +1640,16 @@ public class Core implements IdentityListener { /* TODO */ } + // + // INTERFACE UpdateListener + // + + /** + * {@inheritDoc} + */ + @Override + public void updateFound(Version version, long releaseTime) { + coreListenerManager.fireUpdateFound(version, releaseTime); + } + } diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListener.java b/src/main/java/net/pterodactylus/sone/core/CoreListener.java index 5d5e715..5fbb333 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListener.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListener.java @@ -22,6 +22,7 @@ import java.util.EventListener; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.version.Version; /** * Listener interface for objects that want to be notified on certain @@ -127,4 +128,14 @@ public interface CoreListener extends EventListener { */ public void soneUnlocked(Sone sone); + /** + * Notifies a listener that a new version has been found. + * + * @param version + * The version that was found + * @param releaseTime + * The release time of the new version + */ + public void updateFound(Version version, long releaseTime); + } diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java index 464342c..4fc9532 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java @@ -21,6 +21,7 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.util.event.AbstractListenerManager; +import net.pterodactylus.util.version.Version; /** * Manager for {@link CoreListener}s. @@ -197,4 +198,19 @@ public class CoreListenerManager extends AbstractListenerManager soneUskCallbacks = new HashMap(); + /** The not-Sone-related USK callbacks. */ + private final Map uriUskCallbacks = Collections.synchronizedMap(new HashMap()); + /** * Creates a new Freenet interface. * @@ -197,4 +201,83 @@ public class FreenetInterface { } } + /** + * Registers an arbitrary URI and calls the given callback if a new edition + * is found. + * + * @param uri + * The URI to watch + * @param callback + * The callback to call + */ + public void registerUsk(FreenetURI uri, final Callback callback) { + USKCallback uskCallback = new USKCallback() { + + @Override + public void onFoundEdition(long edition, USK key, ObjectContainer objectContainer, ClientContext clientContext, boolean metadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) { + callback.editionFound(key.getURI(), edition, newKnownGood, newSlotToo); + } + + @Override + public short getPollingPriorityNormal() { + return RequestStarter.PREFETCH_PRIORITY_CLASS; + } + + @Override + public short getPollingPriorityProgress() { + return RequestStarter.INTERACTIVE_PRIORITY_CLASS; + } + + }; + try { + node.clientCore.uskManager.subscribe(USK.create(uri), uskCallback, true, (HighLevelSimpleClientImpl) client); + uriUskCallbacks.put(uri, uskCallback); + } catch (MalformedURLException mue1) { + logger.log(Level.WARNING, "Could not subscribe to USK: " + uri, uri); + } + } + + /** + * Unregisters the USK watcher for the given URI. + * + * @param uri + * The URI to unregister the USK watcher for + */ + public void unregisterUsk(FreenetURI uri) { + USKCallback uskCallback = uriUskCallbacks.remove(uri); + if (uskCallback == null) { + logger.log(Level.INFO, "Could not unregister unknown USK: " + uri); + return; + } + try { + node.clientCore.uskManager.unsubscribe(USK.create(uri), uskCallback); + } catch (MalformedURLException mue1) { + logger.log(Level.INFO, "Could not unregister invalid USK: " + uri); + } + } + + /** + * Callback for USK watcher events. + * + * @author David ‘Bombe’ Roden + */ + public static interface Callback { + + /** + * Notifies a listener that a new edition was found for a URI. + * + * @param uri + * The URI that a new edition was found for + * @param edition + * The found edition + * @param newKnownGood + * Whether the found edition was actually fetched + * @param newSlot + * Whether the found edition is higher than all previously + * found editions + */ + public void editionFound(FreenetURI uri, long edition, boolean newKnownGood, boolean newSlot); + + } + } diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java new file mode 100644 index 0000000..0839cb9 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java @@ -0,0 +1,233 @@ +/* + * Sone - UpdateChecker.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.core; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.util.Date; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.pterodactylus.sone.main.SonePlugin; +import net.pterodactylus.util.collection.Pair; +import net.pterodactylus.util.io.Closer; +import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.version.Version; +import freenet.client.FetchResult; +import freenet.keys.FreenetURI; +import freenet.support.api.Bucket; + +/** + * Watches the official Sone homepage for new releases. + * + * @author David ‘Bombe’ Roden + */ +public class UpdateChecker { + + /** The logger. */ + private static final Logger logger = Logging.getLogger(UpdateChecker.class); + + /** The key of the Sone homepage. */ + private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/"; + + /** The current latest known edition. */ + private static final int LATEST_EDITION = 23; + + /** The Freenet interface. */ + private final FreenetInterface freenetInterface; + + /** The update listener manager. */ + private final UpdateListenerManager updateListenerManager = new UpdateListenerManager(); + + /** The current URI of the homepage. */ + private FreenetURI currentUri; + + /** The current latest known version. */ + private Version currentLatestVersion = SonePlugin.VERSION; + + /** The release date of the latest version. */ + private long latestVersionDate; + + /** + * Creates a new update checker. + * + * @param freenetInterface + * The freenet interface to use + */ + public UpdateChecker(FreenetInterface freenetInterface) { + this.freenetInterface = freenetInterface; + } + + // + // EVENT LISTENER MANAGEMENT + // + + /** + * Adds the given listener to the list of registered listeners. + * + * @param updateListener + * The listener to add + */ + public void addUpdateListener(UpdateListener updateListener) { + updateListenerManager.addListener(updateListener); + } + + /** + * Removes the given listener from the list of registered listeners. + * + * @param updateListener + * The listener to remove + */ + public void removeUpdateListener(UpdateListener updateListener) { + updateListenerManager.removeListener(updateListener); + } + + // + // ACCESSORS + // + + /** + * Returns whether a version that is later than the currently running + * version has been found. + * + * @return {@code true} if a new version was found + */ + public boolean hasLatestVersion() { + return currentLatestVersion.compareTo(SonePlugin.VERSION) > 0; + } + + /** + * Returns the latest version. If no new latest version has been found, the + * current version is returned. + * + * @return The latest known version + */ + public Version getLatestVersion() { + return currentLatestVersion; + } + + /** + * Returns the release time of the latest version. If no new latest version + * has been found, the returned value is undefined. + * + * @return The release time of the latest version, if a new version was + * found + */ + public long getLatestVersionDate() { + return latestVersionDate; + } + + // + // ACTIONS + // + + /** + * Starts the update checker. + */ + public void start() { + try { + currentUri = new FreenetURI(SONE_HOMEPAGE + LATEST_EDITION); + } catch (MalformedURLException mue1) { + /* this can not really happen unless I screw up. */ + logger.log(Level.SEVERE, "Sone Homepage URI invalid!", mue1); + } + freenetInterface.registerUsk(currentUri, new FreenetInterface.Callback() { + + @Override + @SuppressWarnings("synthetic-access") + public void editionFound(FreenetURI uri, long edition, boolean newKnownGood, boolean newSlot) { + logger.log(Level.FINEST, "Found update for %s: %d, %s, %s", new Object[] { uri, edition, newKnownGood, newSlot }); + if (newKnownGood || newSlot) { + Pair uriResult = freenetInterface.fetchUri(uri.setMetaString(new String[] { "sone.properties" })); + if (uriResult == null) { + logger.log(Level.WARNING, "Could not fetch properties of latest homepage: %s", uri); + return; + } + Bucket resultBucket = uriResult.getRight().asBucket(); + try { + parseProperties(resultBucket.getInputStream()); + } catch (IOException ioe1) { + logger.log(Level.WARNING, "Could not parse sone.properties of " + uri, ioe1); + } finally { + resultBucket.free(); + } + } + } + }); + } + + /** + * Stops the update checker. + */ + public void stop() { + freenetInterface.unregisterUsk(currentUri); + } + + // + // PRIVATE ACTIONS + // + + /** + * Parses the properties of the latest version and fires events, if + * necessary. + * + * @see UpdateListener#updateFound(Version, long) + * @see UpdateListenerManager#fireUpdateFound(Version, long) + * @param propertiesInputStream + * The input stream to parse + * @throws IOException + * if an I/O error occured + */ + private void parseProperties(InputStream propertiesInputStream) throws IOException { + Properties properties = new Properties(); + InputStreamReader inputStreamReader = null; + try { + inputStreamReader = new InputStreamReader(propertiesInputStream, "UTF-8"); + properties.load(inputStreamReader); + } finally { + Closer.close(inputStreamReader); + } + String versionString = properties.getProperty("CurrentVersion/Version"); + String releaseTimeString = properties.getProperty("CurrentVersion/ReleaseTime"); + if ((versionString == null) || (releaseTimeString == null)) { + logger.log(Level.INFO, "Invalid data parsed from properties."); + return; + } + Version version = Version.parse(versionString); + long releaseTime = 0; + try { + releaseTime = Long.parseLong(releaseTimeString); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + if ((version == null) || (releaseTime == 0)) { + logger.log(Level.INFO, "Could not parse data from properties."); + return; + } + if (version.compareTo(currentLatestVersion) > 0) { + currentLatestVersion = version; + latestVersionDate = releaseTime; + logger.log(Level.INFO, "Found new version: %s (%tc)", new Object[] { version, new Date(releaseTime) }); + updateListenerManager.fireUpdateFound(version, releaseTime); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateListener.java b/src/main/java/net/pterodactylus/sone/core/UpdateListener.java new file mode 100644 index 0000000..1469afa --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/core/UpdateListener.java @@ -0,0 +1,42 @@ +/* + * Sone - UpdateListener.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.core; + +import java.util.EventListener; + +import net.pterodactylus.util.version.Version; + +/** + * Listener interface for {@link UpdateChecker} events. + * + * @author David ‘Bombe’ Roden + */ +public interface UpdateListener extends EventListener { + + /** + * Notifies a listener that a newer version than the current version was + * found. + * + * @param version + * The version that was found + * @param releaseTime + * The release time of the version + */ + public void updateFound(Version version, long releaseTime); + +} diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateListenerManager.java b/src/main/java/net/pterodactylus/sone/core/UpdateListenerManager.java new file mode 100644 index 0000000..3f3b21f --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/core/UpdateListenerManager.java @@ -0,0 +1,55 @@ +/* + * Sone - UpdateListenerManager.java - Copyright © 2011 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.core; + +import net.pterodactylus.util.event.AbstractListenerManager; +import net.pterodactylus.util.version.Version; + +/** + * Listener manager for {@link UpdateListener} events. + * + * @author David ‘Bombe’ Roden + */ +public class UpdateListenerManager extends AbstractListenerManager { + + /** + * Creates a new update listener manager. + */ + public UpdateListenerManager() { + super(null); + } + + // + // ACTIONS + // + + /** + * Notifies all listeners that a new version has been found. + * + * @param version + * The new version + * @param releaseTime + * The release time of the new version + */ + void fireUpdateFound(Version version, long releaseTime) { + for (UpdateListener updateListener : getListeners()) { + updateListener.updateFound(version, releaseTime); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index 68c9d90..a0a22f9 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -78,7 +78,7 @@ public class SonePlugin implements FredPlugin, FredPluginL10n, FredPluginBaseL10 } /** The version. */ - public static final Version VERSION = new Version(0, 3, 6, 5); + public static final Version VERSION = new Version(0, 3, 7); /** The logger. */ private static final Logger logger = Logging.getLogger(SonePlugin.class); @@ -166,28 +166,28 @@ public class SonePlugin implements FredPlugin, FredPluginL10n, FredPluginBaseL10 } } - /* create freenet interface. */ - FreenetInterface freenetInterface = new FreenetInterface(pluginRespirator.getNode()); + boolean startupFailed = true; + try { + /* create freenet interface. */ + FreenetInterface freenetInterface = new FreenetInterface(pluginRespirator.getNode()); - /* create web of trust connector. */ - PluginConnector pluginConnector = new PluginConnector(pluginRespirator); - WebOfTrustConnector webOfTrustConnector = new WebOfTrustConnector(pluginConnector); - identityManager = new IdentityManager(webOfTrustConnector); - identityManager.setContext("Sone"); + /* create web of trust connector. */ + PluginConnector pluginConnector = new PluginConnector(pluginRespirator); + WebOfTrustConnector webOfTrustConnector = new WebOfTrustConnector(pluginConnector); + identityManager = new IdentityManager(webOfTrustConnector); + identityManager.setContext("Sone"); - /* create core. */ - core = new Core(oldConfiguration, freenetInterface, identityManager); + /* create core. */ + core = new Core(oldConfiguration, freenetInterface, identityManager); - /* create the web interface. */ - webInterface = new WebInterface(this); - core.addCoreListener(webInterface); + /* create the web interface. */ + webInterface = new WebInterface(this); + core.addCoreListener(webInterface); - /* create the identity manager. */ - identityManager.addIdentityListener(core); + /* create the identity manager. */ + identityManager.addIdentityListener(core); - /* start core! */ - boolean startupFailed = true; - try { + /* start core! */ core.start(); if ((newConfiguration != null) && (oldConfiguration != newConfiguration)) { logger.log(Level.INFO, "Setting configuration to file-based configuration."); diff --git a/src/main/java/net/pterodactylus/sone/text/FreenetLinkParser.java b/src/main/java/net/pterodactylus/sone/text/FreenetLinkParser.java index 63f68b8..1ef77d2 100644 --- a/src/main/java/net/pterodactylus/sone/text/FreenetLinkParser.java +++ b/src/main/java/net/pterodactylus/sone/text/FreenetLinkParser.java @@ -147,36 +147,35 @@ public class FreenetLinkParser implements Parser { String name = link; logger.log(Level.FINER, "Found link: %s", link); logger.log(Level.FINEST, "Next: %d, CHK: %d, SSK: %d, USK: %d", new Object[] { next, nextChk, nextSsk, nextUsk }); - if (linkType == LinkType.KSK) { - name = link.substring(4); - } else if ((linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) { - if (name.indexOf('/') > -1) { - if (!name.endsWith("/")) { - name = name.substring(name.lastIndexOf('/') + 1); - } else { - if (name.indexOf('/') != name.lastIndexOf('/')) { - name = name.substring(name.lastIndexOf('/', name.lastIndexOf('/') - 1)); - } else { - /* shorten to 5 chars. */ - name = name.substring(4, Math.min(9, name.length())); - } - } - } + + if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) { + FreenetURI uri; if (name.indexOf('?') > -1) { name = name.substring(0, name.indexOf('?')); } - boolean fromPostingSone = false; - if ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) { - try { - new FreenetURI(link); - fromPostingSone = link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId()); - parts.add(fromPostingSone ? createTrustedFreenetLinkPart(link, name) : createFreenetLinkPart(link, name)); - } catch (MalformedURLException mue1) { - /* it’s not a valid link. */ - parts.add(createPlainTextPart(link)); + if (name.endsWith("/")) { + name = name.substring(0, name.length() - 1); + } + try { + uri = new FreenetURI(name); + name = uri.lastMetaString(); + if (name == null) { + name = uri.getDocName(); + } + if (name == null) { + name = link.substring(0, Math.min(9, link.length())); } - } else { + boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId()); parts.add(fromPostingSone ? createTrustedFreenetLinkPart(link, name) : createFreenetLinkPart(link, name)); + } catch (MalformedURLException mue1) { + /* not a valid link, insert as plain text. */ + parts.add(createPlainTextPart(link)); + } catch (NullPointerException npe1) { + /* FreenetURI sometimes throws these, too. */ + parts.add(createPlainTextPart(link)); + } catch (ArrayIndexOutOfBoundsException aioobe1) { + /* oh, and these, too. */ + parts.add(createPlainTextPart(link)); } } else if ((linkType == LinkType.HTTP) || (linkType == LinkType.HTTPS)) { name = link.substring(linkType == LinkType.HTTP ? 7 : 8); diff --git a/src/main/java/net/pterodactylus/sone/web/AboutPage.java b/src/main/java/net/pterodactylus/sone/web/AboutPage.java index c20c72e..4a0dd22 100644 --- a/src/main/java/net/pterodactylus/sone/web/AboutPage.java +++ b/src/main/java/net/pterodactylus/sone/web/AboutPage.java @@ -17,6 +17,7 @@ package net.pterodactylus.sone.web; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.version.Version; @@ -53,9 +54,9 @@ public class AboutPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); - template.set("version", version); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); + dataProvider.set("version", version); } } diff --git a/src/main/java/net/pterodactylus/sone/web/CreatePostPage.java b/src/main/java/net/pterodactylus/sone/web/CreatePostPage.java index a8e2128..aba4700 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreatePostPage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreatePostPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class CreatePostPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); if (request.getMethod() == Method.POST) { String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim(); @@ -61,9 +62,9 @@ public class CreatePostPage extends SoneTemplatePage { webInterface.getCore().createPost(currentSone, recipient, System.currentTimeMillis(), text); throw new RedirectException(returnPage); } - template.set("errorTextEmpty", true); + dataProvider.set("errorTextEmpty", true); } - template.set("returnPage", returnPage); + dataProvider.set("returnPage", returnPage); } } diff --git a/src/main/java/net/pterodactylus/sone/web/CreateReplyPage.java b/src/main/java/net/pterodactylus/sone/web/CreateReplyPage.java index 2bfab6f..d4a9775 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateReplyPage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateReplyPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class CreateReplyPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String postId = request.getHttpRequest().getPartAsStringFailsafe("post", 36); String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim(); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); @@ -61,11 +62,11 @@ public class CreateReplyPage extends SoneTemplatePage { webInterface.getCore().createReply(currentSone, post, text); throw new RedirectException(returnPage); } - template.set("errorTextEmpty", true); + dataProvider.set("errorTextEmpty", true); } - template.set("postId", postId); - template.set("text", text); - template.set("returnPage", returnPage); + dataProvider.set("postId", postId); + dataProvider.set("text", text); + dataProvider.set("returnPage", returnPage); } } diff --git a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java index 1c16d31..04b5d37 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java @@ -30,6 +30,7 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.wot.OwnIdentity; import net.pterodactylus.sone.web.page.Page.Request.Method; import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.ToadletContext; @@ -93,10 +94,10 @@ public class CreateSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); List ownIdentitiesWithoutSone = getOwnIdentitiesWithoutSone(webInterface.getCore()); - template.set("identitiesWithoutSone", ownIdentitiesWithoutSone); + dataProvider.set("identitiesWithoutSone", ownIdentitiesWithoutSone); if (request.getMethod() == Method.POST) { String id = request.getHttpRequest().getPartAsStringFailsafe("identity", 44); OwnIdentity selectedIdentity = null; @@ -107,7 +108,7 @@ public class CreateSonePage extends SoneTemplatePage { } } if (selectedIdentity == null) { - template.set("errorNoIdentity", true); + dataProvider.set("errorNoIdentity", true); return; } /* create Sone. */ diff --git a/src/main/java/net/pterodactylus/sone/web/DeletePostPage.java b/src/main/java/net/pterodactylus/sone/web/DeletePostPage.java index 4a64ad0..5722ee3 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeletePostPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeletePostPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,14 +50,14 @@ public class DeletePostPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.GET) { String postId = request.getHttpRequest().getParam("post"); String returnPage = request.getHttpRequest().getParam("returnPage"); Post post = webInterface.getCore().getPost(postId); - template.set("post", post); - template.set("returnPage", returnPage); + dataProvider.set("post", post); + dataProvider.set("returnPage", returnPage); return; } else if (request.getMethod() == Method.POST) { String postId = request.getHttpRequest().getPartAsStringFailsafe("post", 36); @@ -72,8 +73,8 @@ public class DeletePostPage extends SoneTemplatePage { } else if (request.getHttpRequest().isPartSet("abortDelete")) { throw new RedirectException(returnPage); } - template.set("post", post); - template.set("returnPage", returnPage); + dataProvider.set("post", post); + dataProvider.set("returnPage", returnPage); } } diff --git a/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java b/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java index 00a1a0e..8d90474 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class DeleteReplyPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String replyId = request.getHttpRequest().getPartAsStringFailsafe("reply", 36); Reply reply = webInterface.getCore().getReply(replyId); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); @@ -66,8 +67,8 @@ public class DeleteReplyPage extends SoneTemplatePage { throw new RedirectException(returnPage); } } - template.set("reply", reply); - template.set("returnPage", returnPage); + dataProvider.set("reply", reply); + dataProvider.set("returnPage", returnPage); } } diff --git a/src/main/java/net/pterodactylus/sone/web/DeleteSonePage.java b/src/main/java/net/pterodactylus/sone/web/DeleteSonePage.java index ae01573..abe26ea 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeleteSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeleteSonePage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -50,8 +51,8 @@ public class DeleteSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.POST) { if (request.getHttpRequest().isPartSet("deleteSone")) { Sone currentSone = getCurrentSone(request.getToadletContext()); diff --git a/src/main/java/net/pterodactylus/sone/web/DismissNotificationPage.java b/src/main/java/net/pterodactylus/sone/web/DismissNotificationPage.java index b1838da..2d61a95 100644 --- a/src/main/java/net/pterodactylus/sone/web/DismissNotificationPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DismissNotificationPage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.util.notify.Notification; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -47,8 +48,8 @@ public class DismissNotificationPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String notificationId = request.getHttpRequest().getPartAsStringFailsafe("notification", 36); Notification notification = webInterface.getNotifications().getNotification(notificationId); if ((notification != null) && notification.isDismissable()) { diff --git a/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java b/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java index 965caf9..01d4815 100644 --- a/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java +++ b/src/main/java/net/pterodactylus/sone/web/EditProfilePage.java @@ -21,6 +21,7 @@ import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; import net.pterodactylus.util.number.Numbers; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.ToadletContext; @@ -51,8 +52,8 @@ public class EditProfilePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); ToadletContext toadletContenxt = request.getToadletContext(); Sone currentSone = getCurrentSone(toadletContenxt); Profile profile = currentSone.getProfile(); @@ -78,12 +79,12 @@ public class EditProfilePage extends SoneTemplatePage { } throw new RedirectException("index.html"); } - template.set("firstName", firstName); - template.set("middleName", middleName); - template.set("lastName", lastName); - template.set("birthDay", birthDay); - template.set("birthMonth", birthMonth); - template.set("birthYear", birthYear); + dataProvider.set("firstName", firstName); + dataProvider.set("middleName", middleName); + dataProvider.set("lastName", lastName); + dataProvider.set("birthDay", birthDay); + dataProvider.set("birthMonth", birthMonth); + dataProvider.set("birthYear", birthYear); } } diff --git a/src/main/java/net/pterodactylus/sone/web/FollowSonePage.java b/src/main/java/net/pterodactylus/sone/web/FollowSonePage.java index c71c280..864480a 100644 --- a/src/main/java/net/pterodactylus/sone/web/FollowSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/FollowSonePage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -46,8 +47,8 @@ public class FollowSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.POST) { String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); diff --git a/src/main/java/net/pterodactylus/sone/web/IndexPage.java b/src/main/java/net/pterodactylus/sone/web/IndexPage.java index a33072f..b0a27f7 100644 --- a/src/main/java/net/pterodactylus/sone/web/IndexPage.java +++ b/src/main/java/net/pterodactylus/sone/web/IndexPage.java @@ -24,6 +24,9 @@ import java.util.List; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.collection.Pagination; +import net.pterodactylus.util.number.Numbers; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -52,8 +55,8 @@ public class IndexPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); Sone currentSone = getCurrentSone(request.getToadletContext()); List allPosts = new ArrayList(); allPosts.addAll(currentSone.getPosts()); @@ -71,16 +74,18 @@ public class IndexPage extends SoneTemplatePage { } } Collections.sort(allPosts, Post.TIME_COMPARATOR); - template.set("posts", allPosts); + Pagination pagination = new Pagination(allPosts, 25).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0)); + dataProvider.set("pagination", pagination); + dataProvider.set("posts", pagination.getItems()); } /** * {@inheritDoc} */ @Override - protected void postProcess(Request request, Template template) { + protected void postProcess(Request request, DataProvider dataProvider) { @SuppressWarnings("unchecked") - List posts = (List) template.get("posts"); + List posts = (List) dataProvider.get("posts"); for (Post post : posts) { webInterface.getCore().markPostKnown(post); for (Reply reply : webInterface.getCore().getReplies(post)) { diff --git a/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java b/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java index d413f61..774f410 100644 --- a/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java +++ b/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -51,11 +52,11 @@ public class KnownSonesPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); List knownSones = new ArrayList(webInterface.getCore().getSones()); Collections.sort(knownSones, Sone.NICE_NAME_COMPARATOR); - template.set("knownSones", knownSones); + dataProvider.set("knownSones", knownSones); } } diff --git a/src/main/java/net/pterodactylus/sone/web/LikePage.java b/src/main/java/net/pterodactylus/sone/web/LikePage.java index dd693ef..c84ea57 100644 --- a/src/main/java/net/pterodactylus/sone/web/LikePage.java +++ b/src/main/java/net/pterodactylus/sone/web/LikePage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class LikePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.POST) { String type=request.getHttpRequest().getPartAsStringFailsafe("type", 16); String id = request.getHttpRequest().getPartAsStringFailsafe(type, 36); diff --git a/src/main/java/net/pterodactylus/sone/web/LockSonePage.java b/src/main/java/net/pterodactylus/sone/web/LockSonePage.java index 05c8ad7..7888659 100644 --- a/src/main/java/net/pterodactylus/sone/web/LockSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/LockSonePage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -48,8 +49,8 @@ public class LockSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); Sone sone = webInterface.getCore().getLocalSone(soneId, false); if (sone != null) { diff --git a/src/main/java/net/pterodactylus/sone/web/LoginPage.java b/src/main/java/net/pterodactylus/sone/web/LoginPage.java index dcfd8a7..ff81562 100644 --- a/src/main/java/net/pterodactylus/sone/web/LoginPage.java +++ b/src/main/java/net/pterodactylus/sone/web/LoginPage.java @@ -26,6 +26,7 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.wot.OwnIdentity; import net.pterodactylus.sone.web.page.Page.Request.Method; import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.ToadletContext; @@ -60,12 +61,12 @@ public class LoginPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); /* get all own identities. */ List localSones = new ArrayList(webInterface.getCore().getLocalSones()); Collections.sort(localSones, Sone.NICE_NAME_COMPARATOR); - template.set("sones", localSones); + dataProvider.set("sones", localSones); if (request.getMethod() == Method.POST) { String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone-id", 100); Sone selectedSone = webInterface.getCore().getLocalSone(soneId, false); @@ -75,7 +76,7 @@ public class LoginPage extends SoneTemplatePage { } } List ownIdentitiesWithoutSone = CreateSonePage.getOwnIdentitiesWithoutSone(webInterface.getCore()); - template.set("identitiesWithoutSone", ownIdentitiesWithoutSone); + dataProvider.set("identitiesWithoutSone", ownIdentitiesWithoutSone); } /** diff --git a/src/main/java/net/pterodactylus/sone/web/LogoutPage.java b/src/main/java/net/pterodactylus/sone/web/LogoutPage.java index f1c0b48..0b6e6e7 100644 --- a/src/main/java/net/pterodactylus/sone/web/LogoutPage.java +++ b/src/main/java/net/pterodactylus/sone/web/LogoutPage.java @@ -17,6 +17,7 @@ package net.pterodactylus.sone.web; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.ToadletContext; @@ -45,9 +46,9 @@ public class LogoutPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { setCurrentSone(request.getToadletContext(), null); - super.processTemplate(request, template); + super.processTemplate(request, dataProvider); throw new RedirectException("index.html"); } diff --git a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java index 77f1a07..63ed6a7 100644 --- a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java +++ b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.core.Options; import net.pterodactylus.sone.web.page.Page.Request.Method; import net.pterodactylus.util.number.Numbers; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class OptionsPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); Options options = webInterface.getCore().getOptions(); if (request.getMethod() == Method.POST) { Integer insertionDelay = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("insertion-delay", 16)); @@ -64,10 +65,10 @@ public class OptionsPage extends SoneTemplatePage { webInterface.getCore().saveConfiguration(); throw new RedirectException(getPath()); } - template.set("insertion-delay", options.getIntegerOption("InsertionDelay").get()); - template.set("sone-rescue-mode", options.getBooleanOption("SoneRescueMode").get()); - template.set("clear-on-next-restart", options.getBooleanOption("ClearOnNextRestart").get()); - template.set("really-clear-on-next-restart", options.getBooleanOption("ReallyClearOnNextRestart").get()); + dataProvider.set("insertion-delay", options.getIntegerOption("InsertionDelay").get()); + dataProvider.set("sone-rescue-mode", options.getBooleanOption("SoneRescueMode").get()); + dataProvider.set("clear-on-next-restart", options.getBooleanOption("ClearOnNextRestart").get()); + dataProvider.set("really-clear-on-next-restart", options.getBooleanOption("ReallyClearOnNextRestart").get()); } } diff --git a/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java b/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java index 23ca247..dc41865 100644 --- a/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java +++ b/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java @@ -21,8 +21,10 @@ import java.util.Arrays; import java.util.Collection; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.web.page.Page; import net.pterodactylus.sone.web.page.TemplatePage; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.SessionManager.Session; import freenet.clients.http.ToadletContext; @@ -184,10 +186,14 @@ public class SoneTemplatePage extends TemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); - template.set("currentSone", getCurrentSone(request.getToadletContext(), false)); - template.set("request", request); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); + dataProvider.set("currentSone", getCurrentSone(request.getToadletContext(), false)); + dataProvider.set("request", request); + dataProvider.set("currentVersion", SonePlugin.VERSION); + dataProvider.set("hasLatestVersion", webInterface.getCore().getUpdateChecker().hasLatestVersion()); + dataProvider.set("latestVersion", webInterface.getCore().getUpdateChecker().getLatestVersion()); + dataProvider.set("latestVersionTime", webInterface.getCore().getUpdateChecker().getLatestVersionDate()); } /** diff --git a/src/main/java/net/pterodactylus/sone/web/UnfollowSonePage.java b/src/main/java/net/pterodactylus/sone/web/UnfollowSonePage.java index 5b0c652..316e408 100644 --- a/src/main/java/net/pterodactylus/sone/web/UnfollowSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/UnfollowSonePage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -46,8 +47,8 @@ public class UnfollowSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.POST) { String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); diff --git a/src/main/java/net/pterodactylus/sone/web/UnlikePage.java b/src/main/java/net/pterodactylus/sone/web/UnlikePage.java index 1ecacc8..d08689f 100644 --- a/src/main/java/net/pterodactylus/sone/web/UnlikePage.java +++ b/src/main/java/net/pterodactylus/sone/web/UnlikePage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.Page.Request.Method; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -49,8 +50,8 @@ public class UnlikePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); if (request.getMethod() == Method.POST) { String type = request.getHttpRequest().getPartAsStringFailsafe("type", 16); String id = request.getHttpRequest().getPartAsStringFailsafe(type, 36); diff --git a/src/main/java/net/pterodactylus/sone/web/UnlockSonePage.java b/src/main/java/net/pterodactylus/sone/web/UnlockSonePage.java index 938e451..35d69ff 100644 --- a/src/main/java/net/pterodactylus/sone/web/UnlockSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/UnlockSonePage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -47,8 +48,8 @@ public class UnlockSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); Sone sone = webInterface.getCore().getLocalSone(soneId, false); if (sone != null) { diff --git a/src/main/java/net/pterodactylus/sone/web/ViewPostPage.java b/src/main/java/net/pterodactylus/sone/web/ViewPostPage.java index 3bc3b36..3c4eddf 100644 --- a/src/main/java/net/pterodactylus/sone/web/ViewPostPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ViewPostPage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -48,19 +49,19 @@ public class ViewPostPage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String postId = request.getHttpRequest().getParam("post"); Post post = webInterface.getCore().getPost(postId); - template.set("post", post); + dataProvider.set("post", post); } /** * {@inheritDoc} */ @Override - protected void postProcess(Request request, Template template) { - Post post = (Post) template.get("post"); + protected void postProcess(Request request, DataProvider dataProvider) { + Post post = (Post) dataProvider.get("post"); webInterface.getCore().markPostKnown(post); for (Reply reply : webInterface.getCore().getReplies(post)) { webInterface.getCore().markReplyKnown(reply); diff --git a/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java b/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java index d933bc7..9fd6fae 100644 --- a/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java @@ -22,6 +22,7 @@ import java.util.List; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; /** @@ -51,19 +52,19 @@ public class ViewSonePage extends SoneTemplatePage { * {@inheritDoc} */ @Override - protected void processTemplate(Request request, Template template) throws RedirectException { - super.processTemplate(request, template); + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); String soneId = request.getHttpRequest().getParam("sone"); Sone sone = webInterface.getCore().getSone(soneId, false); - template.set("sone", sone); + dataProvider.set("sone", sone); } /** * {@inheritDoc} */ @Override - protected void postProcess(Request request, Template template) { - Sone sone = (Sone) template.get("sone"); + protected void postProcess(Request request, DataProvider dataProvider) { + Sone sone = (Sone) dataProvider.get("sone"); List posts = sone.getPosts(); for (Post post : posts) { webInterface.getCore().markPostKnown(post); diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index d3ec1ee..6085ff8 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -88,6 +88,7 @@ import net.pterodactylus.util.template.TemplateFactory; import net.pterodactylus.util.template.TemplateProvider; import net.pterodactylus.util.template.XmlFilter; import net.pterodactylus.util.thread.Ticker; +import net.pterodactylus.util.version.Version; import freenet.clients.http.SessionManager; import freenet.clients.http.SessionManager.Session; import freenet.clients.http.ToadletContainer; @@ -141,6 +142,9 @@ public class WebInterface implements CoreListener { /** The “Sone locked” notification. */ private final ListNotification lockedSonesNotification; + /** The “new version” notification. */ + private final TemplateNotification newVersionNotification; + /** * Creates a new web interface. * @@ -189,6 +193,9 @@ public class WebInterface implements CoreListener { Template lockedSonesTemplate = templateFactory.createTemplate(createReader("/templates/notify/lockedSonesNotification.html")); lockedSonesNotification = new ListNotification("sones-locked-notification", "sones", lockedSonesTemplate); + + Template newVersionTemplate = templateFactory.createTemplate(createReader("/templates/notify/newVersionNotification.html")); + newVersionNotification = new TemplateNotification("new-version-notification", newVersionTemplate); } // @@ -701,6 +708,16 @@ public class WebInterface implements CoreListener { } /** + * {@inheritDoc} + */ + @Override + public void updateFound(Version version, long releaseTime) { + newVersionNotification.set("version", version); + newVersionNotification.set("releaseTime", releaseTime); + notificationManager.addNotification(newVersionNotification); + } + + /** * Template provider implementation that uses * {@link WebInterface#createReader(String)} to load templates for * inclusion. diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java index 015add5..a358fb1 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java @@ -91,13 +91,23 @@ public class GetStatusAjaxPage extends JsonPage { Set newPosts = webInterface.getNewPosts(); JsonArray jsonPosts = new JsonArray(); for (Post post : newPosts) { - jsonPosts.add(post.getId()); + JsonObject jsonPost = new JsonObject(); + jsonPost.put("id", post.getId()); + jsonPost.put("sone", post.getSone().getId()); + jsonPost.put("recipient", (post.getRecipient() != null) ? post.getRecipient().getId() : null); + jsonPost.put("time", post.getTime()); + jsonPosts.add(jsonPost); } /* load new replies. */ Set newReplies = webInterface.getNewReplies(); JsonArray jsonReplies = new JsonArray(); for (Reply reply : newReplies) { - jsonReplies.add(reply.getId()); + JsonObject jsonReply = new JsonObject(); + jsonReply.put("id", reply.getId()); + jsonReply.put("sone", reply.getSone().getId()); + jsonReply.put("post", reply.getPost().getId()); + jsonReply.put("postSone", reply.getPost().getSone().getId()); + jsonReplies.add(jsonReply); } return createSuccessJsonObject().put("sones", jsonSones).put("notifications", jsonNotifications).put("removedNotifications", jsonRemovedNotifications).put("newPosts", jsonPosts).put("newReplies", jsonReplies); } diff --git a/src/main/java/net/pterodactylus/sone/web/page/TemplatePage.java b/src/main/java/net/pterodactylus/sone/web/page/TemplatePage.java index e823eb5..e6ee539 100644 --- a/src/main/java/net/pterodactylus/sone/web/page/TemplatePage.java +++ b/src/main/java/net/pterodactylus/sone/web/page/TemplatePage.java @@ -25,6 +25,7 @@ import java.util.logging.Logger; import net.pterodactylus.sone.web.page.Page.Request.Method; import net.pterodactylus.util.logging.Logging; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import freenet.clients.http.LinkEnabledCallback; import freenet.clients.http.PageMaker; @@ -46,7 +47,7 @@ public class TemplatePage implements Page, LinkEnabledCallback { private final String path; /** The template to render. */ - protected final Template template; + private final Template template; /** The L10n handler. */ private final BaseL10n l10n; @@ -116,9 +117,10 @@ public class TemplatePage implements Page, LinkEnabledCallback { pageNode.addForwardLink("icon", shortcutIcon); } + DataProvider dataProvider = template.createDataProvider(); try { long start = System.nanoTime(); - processTemplate(request, template); + processTemplate(request, dataProvider); long finish = System.nanoTime(); logger.log(Level.FINEST, "Template was rendered in " + ((finish - start) / 1000) / 1000.0 + "ms."); } catch (RedirectException re1) { @@ -126,10 +128,10 @@ public class TemplatePage implements Page, LinkEnabledCallback { } StringWriter stringWriter = new StringWriter(); - template.render(stringWriter); + template.render(dataProvider, stringWriter); pageNode.content.addChild("%", stringWriter.toString()); - postProcess(request, template); + postProcess(request, dataProvider); return new Response(200, "OK", "text/html", pageNode.outer.generate()); } @@ -159,29 +161,29 @@ public class TemplatePage implements Page, LinkEnabledCallback { * * @param request * The request that is rendered - * @param template - * The template to set variables in + * @param dataProvider + * The data provider to set variables in * @throws RedirectException * if the processing page wants to redirect after processing */ - protected void processTemplate(Request request, Template template) throws RedirectException { + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { /* do nothing. */ } /** * This method will be called after - * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, Template)} + * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)} * has processed the template and the template was rendered. This method * will not be called if - * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, Template)} + * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)} * throws a {@link RedirectException}! * * @param request * The request being processed - * @param template - * The template that was rendered + * @param dataProvider + * The data provider that supplied the rendered data */ - protected void postProcess(Request request, Template template) { + protected void postProcess(Request request, DataProvider dataProvider) { /* do nothing. */ } @@ -212,7 +214,7 @@ public class TemplatePage implements Page, LinkEnabledCallback { /** * Exception that can be thrown to signal that a subclassed {@link Page} * wants to redirect the user during the - * {@link TemplatePage#processTemplate(net.pterodactylus.sone.web.page.Page.Request, Template)} + * {@link TemplatePage#processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)} * method call. * * @author David ‘Bombe’ Roden diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index 533a01b..740cf45 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -175,6 +175,8 @@ WebInterface.SelectBox.Choose=Choose… WebInterface.SelectBox.Yes=Yes WebInterface.SelectBox.No=No WebInterface.ClickToShow.Replies=Click here to show hidden replies. +WebInterface.VersionInformation.CurrentVersion=Current Version: +WebInterface.VersionInformation.LatestVersion=Latest Version: Notification.ClickHereToRead=Click here to read the full text of the notification. Notification.FirstStart.Text=This seems to be the first time you start Sone. To start, create a new Sone from a web of trust identity and start following other Sones. @@ -191,3 +193,4 @@ Notification.SoneIsBeingRescued.Text=The following Sones are currently being res Notification.SoneRescued.Text=The following Sones have been rescued: 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=A new version of the Sone plugin was found: Version {version}. diff --git a/src/main/resources/static/css/sone.css b/src/main/resources/static/css/sone.css index 89d9854..4f0c49e 100644 --- a/src/main/resources/static/css/sone.css +++ b/src/main/resources/static/css/sone.css @@ -20,6 +20,13 @@ textarea { height: 4em; } +#sone button { + background-color: #ddd; + border-width: 1px; + color: #444; + padding: 0.5ex 1.5ex; +} + #sone form { margin: 0px; } @@ -444,6 +451,10 @@ textarea { color: #888; } +#sone #tail #version-information { + margin-top: 1em; +} + #sone #add-sone textarea, #sone #create-sone textarea, #sone #load-sone textarea, #sone #edit-profile textarea { height: 1.5em; } diff --git a/src/main/resources/static/javascript/sone.js b/src/main/resources/static/javascript/sone.js index 9aa0b82..3c229e0 100644 --- a/src/main/resources/static/javascript/sone.js +++ b/src/main/resources/static/javascript/sone.js @@ -453,7 +453,7 @@ function ajaxifyPost(postElement) { postReply(postId, text, function(success, error, replyId) { if (success) { $(inputField).val(""); - loadNewReply(replyId); + loadNewReply(replyId, getCurrentSoneId(), postId); markPostAsKnown(getPostElement(inputField)); $("#sone .post#" + postId + " .create-reply").addClass("hidden"); } else { @@ -585,11 +585,11 @@ function getStatus() { }); /* process new posts. */ $.each(data.newPosts, function(index, value) { - loadNewPost(value); + loadNewPost(value.id, value.sone, value.recipient, value.time); }); /* process new replies. */ $.each(data.newReplies, function(index, value) { - loadNewReply(value); + loadNewReply(value.id, value.sone, value.post, value.postSone); }); /* do it again in 5 seconds. */ setTimeout(getStatus, 5000); @@ -604,6 +604,16 @@ function getStatus() { } /** + * Returns the ID of the currently logged in Sone. + * + * @return The ID of the current Sone, or an empty string if no Sone is logged + * in + */ +function getCurrentSoneId() { + return $("#currentSoneId").text(); +} + +/** * Returns the content of the page-id attribute. * * @returns The page ID @@ -696,10 +706,20 @@ function hasReply(replyId) { return $("#sone .reply#" + replyId).length > 0; } -function loadNewPost(postId) { +function loadNewPost(postId, soneId, recipientId, time) { if (hasPost(postId)) { return; } + if (!isIndexPage()) { + if (!isViewPostPage() || (getShownPostId() != postId)) { + if (!isViewSonePage() || ((getShownSoneId() != soneId) && (getShownSoneId() != recipientId))) { + return; + } + } + } + if (getPostTime($("#sone .post").last()) > time) { + return; + } $.getJSON("getPost.ajax", { "post" : postId }, function(data, textStatus) { if ((data != null) && data.success) { if (hasPost(data.post.id)) { @@ -718,8 +738,6 @@ function loadNewPost(postId) { newPost = $(data.post.html).addClass("hidden"); if (firstOlderPost != null) { newPost.insertBefore(firstOlderPost); - } else { - $("#sone #posts").append(newPost); } ajaxifyPost(newPost); newPost.slideDown(); @@ -728,10 +746,13 @@ function loadNewPost(postId) { }); } -function loadNewReply(replyId) { +function loadNewReply(replyId, soneId, postId, postSoneId) { if (hasReply(replyId)) { return; } + if (!hasPost(postId)) { + return; + } $.getJSON("getReply.ajax", { "reply": replyId }, function(data, textStatus) { /* find post. */ if ((data != null) && data.success) { @@ -859,7 +880,7 @@ $(document).ready(function() { text = $(this).find(":input:enabled").val(); $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "text": text }, function(data, textStatus) { if ((data != null) && data.success) { - loadNewPost(data.postId); + loadNewPost(data.postId, getCurrentSoneId()); } }); $(this).find(":input:enabled").val("").blur(); @@ -874,7 +895,7 @@ $(document).ready(function() { text = $(this).find(":input:enabled").val(); $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "recipient": getShownSoneId(), "text": text }, function(data, textStatus) { if ((data != null) && data.success) { - loadNewPost(data.postId); + loadNewPost(data.postId, getCurrentSoneId()); } }); $(this).find(":input:enabled").val("").blur(); diff --git a/src/main/resources/templates/include/head.html b/src/main/resources/templates/include/head.html index 1d8e284..2c2cf3f 100644 --- a/src/main/resources/templates/include/head.html +++ b/src/main/resources/templates/include/head.html @@ -1,6 +1,7 @@
<% formPassword|html>
+ diff --git a/src/main/resources/templates/include/tail.html b/src/main/resources/templates/include/tail.html index 180bcf2..dd2e25e 100644 --- a/src/main/resources/templates/include/tail.html +++ b/src/main/resources/templates/include/tail.html @@ -7,6 +7,13 @@ Flattr Sone
+ +
+
<%= WebInterface.VersionInformation.CurrentVersion|l10n|html> <% currentVersion|html>
+ <%if hasLatestVersion> +
<%= WebInterface.VersionInformation.LatestVersion|l10n|html> <% latestVersion|html>
+ <%/if> +
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 39d53f1..345f376 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -5,8 +5,6 @@

<%= Page.Index.PostList.Title|l10n|html>

- <%getpage> - <%paginate list=posts pagesize=25> <%= page|store key=pageParameter> <%include include/pagination.html> <%foreach pagination.items post> diff --git a/src/main/resources/templates/notify/newVersionNotification.html b/src/main/resources/templates/notify/newVersionNotification.html new file mode 100644 index 0000000..23a5855 --- /dev/null +++ b/src/main/resources/templates/notify/newVersionNotification.html @@ -0,0 +1 @@ +
<%= Notification.NewVersion.Text|l10n|html|replace needle="{version}" replacementKey=version>