From: David ‘Bombe’ Roden Date: Sat, 15 Jan 2011 20:30:26 +0000 (+0100) Subject: Merge branch 'edit-wot-trust' into next X-Git-Tag: 0.4^2~8 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=f4ea1e1b3526175e255831c975d6eea813589f25;hp=76e7a20f5212d9c202dbe92e958834ce3f99bd0e Merge branch 'edit-wot-trust' into next Conflicts: src/main/java/net/pterodactylus/sone/core/Core.java src/main/java/net/pterodactylus/sone/web/OptionsPage.java src/main/java/net/pterodactylus/sone/web/WebInterface.java --- diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index a1282cc..27e8db8 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -41,11 +41,14 @@ import net.pterodactylus.sone.freenet.wot.Identity; import net.pterodactylus.sone.freenet.wot.IdentityListener; import net.pterodactylus.sone.freenet.wot.IdentityManager; import net.pterodactylus.sone.freenet.wot.OwnIdentity; +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.sone.freenet.wot.WebOfTrustException; import net.pterodactylus.sone.main.SonePlugin; 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.validation.Validation; import net.pterodactylus.util.version.Version; import freenet.keys.FreenetURI; @@ -152,6 +155,9 @@ public class Core implements IdentityListener, UpdateListener { /** All known replies. */ private Set knownReplies = new HashSet(); + /** Trusted identities, sorted by own identities. */ + private Map> trustedIdentities = Collections.synchronizedMap(new HashMap>()); + /** * Creates a new core. * @@ -518,6 +524,19 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Returns whether the target Sone is trusted by the origin Sone. + * + * @param origin + * The origin Sone + * @param target + * The target Sone + * @return {@code true} if the target Sone is trusted by the origin Sone + */ + public boolean isSoneTrusted(Sone origin, Sone target) { + return trustedIdentities.containsKey(origin) && trustedIdentities.get(origin.getIdentity()).contains(target); + } + + /** * Returns the post with the given ID. * * @param postId @@ -840,7 +859,12 @@ public class Core implements IdentityListener, UpdateListener { * @return The created Sone */ public Sone createSone(OwnIdentity ownIdentity) { - identityManager.addContext(ownIdentity, "Sone"); + try { + ownIdentity.addContext("Sone"); + } catch (WebOfTrustException wote1) { + logger.log(Level.SEVERE, "Could not add “Sone” context to own identity: " + ownIdentity, wote1); + return null; + } Sone sone = addLocalSone(ownIdentity); return sone; } @@ -890,6 +914,97 @@ public class Core implements IdentityListener, UpdateListener { } /** + * Retrieves the trust relationship from the origin to the target. If the + * trust relationship can not be retrieved, {@code null} is returned. + * + * @see Identity#getTrust(OwnIdentity) + * @param origin + * The origin of the trust tree + * @param target + * The target of the trust + * @return The trust relationship + */ + public Trust getTrust(Sone origin, Sone target) { + if (!isLocalSone(origin)) { + logger.log(Level.WARNING, "Tried to get trust from remote Sone: %s", origin); + return null; + } + return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity()); + } + + /** + * Sets the trust value of the given origin Sone for the target Sone. + * + * @param origin + * The origin Sone + * @param target + * The target Sone + * @param trustValue + * The trust value (from {@code -100} to {@code 100}) + */ + public void setTrust(Sone origin, Sone target, int trustValue) { + Validation.begin().isNotNull("Trust Origin", origin).check().isInstanceOf("Trust Origin", origin.getIdentity(), OwnIdentity.class).isNotNull("Trust Target", target).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check(); + try { + ((OwnIdentity) origin.getIdentity()).setTrust(target.getIdentity(), trustValue, options.getStringOption("TrustComment").get()); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not set trust for Sone: " + target, wote1); + } + } + + /** + * Removes any trust assignment for the given target Sone. + * + * @param origin + * The trust origin + * @param target + * The trust target + */ + public void removeTrust(Sone origin, Sone target) { + Validation.begin().isNotNull("Trust Origin", origin).isNotNull("Trust Target", target).check().isInstanceOf("Trust Origin Identity", origin.getIdentity(), OwnIdentity.class).check(); + try { + ((OwnIdentity) origin.getIdentity()).removeTrust(target.getIdentity()); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not remove trust for Sone: " + target, wote1); + } + } + + /** + * Assigns the configured positive trust value for the given target. + * + * @param origin + * The trust origin + * @param target + * The trust target + */ + public void trustSone(Sone origin, Sone target) { + setTrust(origin, target, options.getIntegerOption("PositiveTrust").get()); + } + + /** + * Assigns the configured negative trust value for the given target. + * + * @param origin + * The trust origin + * @param target + * The trust target + */ + public void distrustSone(Sone origin, Sone target) { + setTrust(origin, target, options.getIntegerOption("NegativeTrust").get()); + } + + /** + * Removes the trust assignment for the given target. + * + * @param origin + * The trust origin + * @param target + * The trust target + */ + public void untrustSone(Sone origin, Sone target) { + removeTrust(origin, target); + } + + /** * Updates the stores Sone with the given Sone. * * @param sone @@ -994,8 +1109,12 @@ public class Core implements IdentityListener, UpdateListener { localSones.remove(sone.getId()); soneInserters.remove(sone).stop(); } - identityManager.removeContext((OwnIdentity) sone.getIdentity(), "Sone"); - identityManager.removeProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition"); + try { + ((OwnIdentity) sone.getIdentity()).removeContext("Sone"); + ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition"); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not remove context and properties from Sone: " + sone, wote1); + } try { configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null); } catch (ConfigurationException ce1) { @@ -1161,8 +1280,9 @@ public class Core implements IdentityListener, UpdateListener { } logger.log(Level.INFO, "Saving Sone: %s", sone); - identityManager.setProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); try { + ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); + /* save Sone into configuration. */ String sonePrefix = "Sone/" + sone.getId(); configuration.getLongValue(sonePrefix + "/Time").setValue(sone.getTime()); @@ -1233,6 +1353,8 @@ public class Core implements IdentityListener, UpdateListener { logger.log(Level.INFO, "Sone %s saved.", sone); } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not save Sone: " + sone, ce1); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "Could not set WoT property for Sone: " + sone, wote1); } } @@ -1471,6 +1593,9 @@ public class Core implements IdentityListener, UpdateListener { try { configuration.getIntValue("Option/ConfigurationVersion").setValue(0); configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal()); + configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal()); + configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal()); + configuration.getStringValue("Option/TrustComment").setValue(options.getStringOption("TrustComment").getReal()); configuration.getBooleanValue("Option/SoneRescueMode").setValue(options.getBooleanOption("SoneRescueMode").getReal()); configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal()); configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal()); @@ -1532,6 +1657,9 @@ public class Core implements IdentityListener, UpdateListener { } })); + options.addIntegerOption("PositiveTrust", new DefaultOption(75)); + options.addIntegerOption("NegativeTrust", new DefaultOption(-100)); + options.addStringOption("TrustComment", new DefaultOption("Set from Sone Web Interface")); options.addBooleanOption("SoneRescueMode", new DefaultOption(false)); options.addBooleanOption("ClearOnNextRestart", new DefaultOption(false)); options.addBooleanOption("ReallyClearOnNextRestart", new DefaultOption(false)); @@ -1548,6 +1676,9 @@ public class Core implements IdentityListener, UpdateListener { } options.getIntegerOption("InsertionDelay").set(configuration.getIntValue("Option/InsertionDelay").getValue(null)); + options.getIntegerOption("PositiveTrust").set(configuration.getIntValue("Option/PositiveTrust").getValue(null)); + options.getIntegerOption("NegativeTrust").set(configuration.getIntValue("Option/NegativeTrust").getValue(null)); + options.getStringOption("TrustComment").set(configuration.getStringValue("Option/TrustComment").getValue(null)); options.getBooleanOption("SoneRescueMode").set(configuration.getBooleanValue("Option/SoneRescueMode").getValue(null)); /* load known Sones. */ @@ -1616,6 +1747,7 @@ public class Core implements IdentityListener, UpdateListener { public void ownIdentityAdded(OwnIdentity ownIdentity) { logger.log(Level.FINEST, "Adding OwnIdentity: " + ownIdentity); if (ownIdentity.hasContext("Sone")) { + trustedIdentities.put(ownIdentity, Collections.synchronizedSet(new HashSet())); addLocalSone(ownIdentity); } } @@ -1626,14 +1758,16 @@ public class Core implements IdentityListener, UpdateListener { @Override public void ownIdentityRemoved(OwnIdentity ownIdentity) { logger.log(Level.FINEST, "Removing OwnIdentity: " + ownIdentity); + trustedIdentities.remove(ownIdentity); } /** * {@inheritDoc} */ @Override - public void identityAdded(Identity identity) { + public void identityAdded(OwnIdentity ownIdentity, Identity identity) { logger.log(Level.FINEST, "Adding Identity: " + identity); + trustedIdentities.get(ownIdentity).add(identity); addRemoteSone(identity); } @@ -1641,13 +1775,14 @@ public class Core implements IdentityListener, UpdateListener { * {@inheritDoc} */ @Override - public void identityUpdated(final Identity identity) { + public void identityUpdated(OwnIdentity ownIdentity, final Identity identity) { new Thread(new Runnable() { @Override @SuppressWarnings("synthetic-access") public void run() { Sone sone = getRemoteSone(identity.getId()); + sone.setIdentity(identity); soneDownloader.fetchSone(sone); } }).start(); @@ -1657,8 +1792,8 @@ public class Core implements IdentityListener, UpdateListener { * {@inheritDoc} */ @Override - public void identityRemoved(Identity identity) { - /* TODO */ + public void identityRemoved(OwnIdentity ownIdentity, Identity identity) { + trustedIdentities.get(ownIdentity).remove(identity); } // diff --git a/src/main/java/net/pterodactylus/sone/core/Options.java b/src/main/java/net/pterodactylus/sone/core/Options.java index f77c085..b7ece81 100644 --- a/src/main/java/net/pterodactylus/sone/core/Options.java +++ b/src/main/java/net/pterodactylus/sone/core/Options.java @@ -161,6 +161,9 @@ public class Options { /** Holds all {@link Integer} {@link Option}s. */ private final Map> integerOptions = Collections.synchronizedMap(new HashMap>()); + /** Holds all {@link String} {@link Option}s. */ + private final Map> stringOptions = Collections.synchronizedMap(new HashMap>()); + /** * Adds a boolean option. * @@ -213,4 +216,30 @@ public class Options { return integerOptions.get(name); } + /** + * Adds a {@link String} {@link Option}. + * + * @param name + * The name of the option + * @param stringOption + * The option + * @return The given option + */ + public Option addStringOption(String name, Option stringOption) { + stringOptions.put(name, stringOption); + return stringOption; + } + + /** + * Returns a {@link String} {@link Option}. + * + * @param name + * The name of the string option to get + * @return The string option, or {@code null} if there is no option with the + * given name + */ + public Option getStringOption(String name) { + return stringOptions.get(name); + } + } diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java new file mode 100644 index 0000000..71710e4 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListener.java @@ -0,0 +1,51 @@ +/* + * Sone - ConnectorListener.java - Copyright © 2010 David Roden + * + * This 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.freenet.plugin; + +import java.util.EventListener; + + +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Interface for objects that want to be notified if a {@link PluginConnector} + * receives a reply from a plugin. As a connection listener is always + * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener) + * added} for a specific plugin, it will always be notified for replies from the + * correct plugin (unless you register the same listener for multiple + * plugins—which you subsequently should not do). + * + * @author David ‘Bombe’ Roden + */ +public interface ConnectorListener extends EventListener { + + /** + * A reply was received from the plugin this connection listener was added + * for. + * + * @param pluginConnector + * The plugin connector that received the reply + * @param fields + * The fields of the reply + * @param data + * The data of the reply (may be null) + */ + public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data); + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java new file mode 100644 index 0000000..7021332 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/ConnectorListenerManager.java @@ -0,0 +1,60 @@ +/* + * Sone - ConnectorListenerManager.java - Copyright © 2010 David Roden + * + * This 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.freenet.plugin; + +import net.pterodactylus.util.event.AbstractListenerManager; +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Manages {@link ConnectorListener}s and fire events. + * + * @author David ‘Bombe’ Roden + */ +public class ConnectorListenerManager extends AbstractListenerManager { + + /** + * Creates a new manager for {@link ConnectorListener}s. + * + * @param pluginConnector + * The plugin connector that is the source for all events + */ + public ConnectorListenerManager(PluginConnector pluginConnector) { + super(pluginConnector); + } + + // + // ACTIONS + // + + /** + * Notifies all registered listeners that a reply from the plugin was + * received. + * + * @param fields + * The fields of the reply + * @param data + * The data of the reply (may be null) + */ + public void fireReceivedReply(SimpleFieldSet fields, Bucket data) { + for (ConnectorListener connectorListener : getListeners()) { + connectorListener.receivedReply(getSource(), fields, data); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java new file mode 100644 index 0000000..e7bf828 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginConnector.java @@ -0,0 +1,203 @@ +/* + * Sone - PluginConnector.java - Copyright © 2010 David Roden + * + * This 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.freenet.plugin; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import net.pterodactylus.util.collection.Pair; +import freenet.pluginmanager.FredPluginTalker; +import freenet.pluginmanager.PluginNotFoundException; +import freenet.pluginmanager.PluginRespirator; +import freenet.pluginmanager.PluginTalker; +import freenet.support.SimpleFieldSet; +import freenet.support.api.Bucket; + +/** + * Interface for talking to other plugins. Other plugins are identified by their + * name and a unique connection identifier. + * + * @author David ‘Bombe’ Roden + */ +public class PluginConnector implements FredPluginTalker { + + /** The plugin respirator. */ + private final PluginRespirator pluginRespirator; + + /** Connector listener managers for all plugin connections. */ + private final Map, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap, ConnectorListenerManager>()); + + /** + * Creates a new plugin connector. + * + * @param pluginRespirator + * The plugin respirator + */ + public PluginConnector(PluginRespirator pluginRespirator) { + this.pluginRespirator = pluginRespirator; + } + + // + // LISTENER MANAGEMENT + // + + /** + * Adds a connection listener for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param connectorListener + * The listener to add + */ + public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { + getConnectorListenerManager(pluginName, identifier).addListener(connectorListener); + } + + /** + * Removes a connection listener for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param connectorListener + * The listener to remove + */ + public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { + getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener); + } + + // + // ACTIONS + // + + /** + * Sends a request to the given plugin. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param fields + * The fields of the message + * @throws PluginException + * if the plugin can not be found + */ + public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields) throws PluginException { + sendRequest(pluginName, identifier, fields, null); + } + + /** + * Sends a request to the given plugin. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param fields + * The fields of the message + * @param data + * The payload of the message (may be null) + * @throws PluginException + * if the plugin can not be found + */ + public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields, Bucket data) throws PluginException { + getPluginTalker(pluginName, identifier).send(fields, data); + } + + // + // PRIVATE METHODS + // + + /** + * Returns the connection listener manager for the given plugin connection, + * creating a new one if none does exist yet. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @return The connection listener manager + */ + private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) { + return getConnectorListenerManager(pluginName, identifier, true); + } + + /** + * Returns the connection listener manager for the given plugin connection, + * optionally creating a new one if none does exist yet. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @param create + * {@code true} to create a new manager if there is none, + * {@code false} to return {@code null} in that case + * @return The connection listener manager, or {@code null} if none existed + * and {@code create} is {@code false} + */ + private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) { + ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new Pair(pluginName, identifier)); + if (create && (connectorListenerManager == null)) { + connectorListenerManager = new ConnectorListenerManager(this); + connectorListenerManagers.put(new Pair(pluginName, identifier), connectorListenerManager); + } + return connectorListenerManager; + } + + /** + * Returns the plugin talker for the given plugin connection. + * + * @param pluginName + * The name of the plugin + * @param identifier + * The identifier of the connection + * @return The plugin talker + * @throws PluginException + * if the plugin can not be found + */ + private PluginTalker getPluginTalker(String pluginName, String identifier) throws PluginException { + try { + return pluginRespirator.getPluginTalker(this, pluginName, identifier); + } catch (PluginNotFoundException pnfe1) { + throw new PluginException(pnfe1); + } + } + + // + // INTERFACE FredPluginTalker + // + + /** + * {@inheritDoc} + */ + @Override + public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) { + ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false); + if (connectorListenerManager == null) { + /* we don’t care about events for this plugin. */ + return; + } + connectorListenerManager.fireReceivedReply(params, data); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java new file mode 100644 index 0000000..0e1af2b --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/plugin/PluginException.java @@ -0,0 +1,68 @@ +/* + * Sone - PluginException.java - Copyright © 2010 David Roden + * + * This 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.freenet.plugin; + +import net.pterodactylus.sone.freenet.wot.WebOfTrustException; + +/** + * Exception that signals an error when communicating with a plugin. + * + * @author David ‘Bombe’ Roden + */ +public class PluginException extends WebOfTrustException { + + /** + * Creates a new plugin exception. + */ + public PluginException() { + super(); + } + + /** + * Creates a new plugin exception. + * + * @param message + * The message of the exception + */ + public PluginException(String message) { + super(message); + } + + /** + * Creates a new plugin exception. + * + * @param cause + * The cause of the exception + */ + public PluginException(Throwable cause) { + super(cause); + } + + /** + * Creates a new plugin exception. + * + * @param message + * The message of the exception + * @param cause + * The cause of the exception + */ + public PluginException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java b/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java deleted file mode 100644 index cf1d1e3..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Sone - ConnectorListener.java - Copyright © 2010 David Roden - * - * This 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.freenet.wot; - -import java.util.EventListener; - -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Interface for objects that want to be notified if a {@link PluginConnector} - * receives a reply from a plugin. As a connection listener is always - * {@link PluginConnector#addConnectorListener(String, String, ConnectorListener) - * added} for a specific plugin, it will always be notified for replies from the - * correct plugin (unless you register the same listener for multiple - * plugins—which you subsequently should not do). - * - * @author David ‘Bombe’ Roden - */ -public interface ConnectorListener extends EventListener { - - /** - * A reply was received from the plugin this connection listener was added - * for. - * - * @param pluginConnector - * The plugin connector that received the reply - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data); - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java deleted file mode 100644 index 3962eef..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/ConnectorListenerManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Sone - ConnectorListenerManager.java - Copyright © 2010 David Roden - * - * This 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.freenet.wot; - -import net.pterodactylus.util.event.AbstractListenerManager; -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Manages {@link ConnectorListener}s and fire events. - * - * @author David ‘Bombe’ Roden - */ -public class ConnectorListenerManager extends AbstractListenerManager { - - /** - * Creates a new manager for {@link ConnectorListener}s. - * - * @param pluginConnector - * The plugin connector that is the source for all events - */ - public ConnectorListenerManager(PluginConnector pluginConnector) { - super(pluginConnector); - } - - // - // ACTIONS - // - - /** - * Notifies all registered listeners that a reply from the plugin was - * received. - * - * @param fields - * The fields of the reply - * @param data - * The data of the reply (may be null) - */ - public void fireReceivedReply(SimpleFieldSet fields, Bucket data) { - for (ConnectorListener connectorListener : getListeners()) { - connectorListener.receivedReply(getSource(), fields, data); - } - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java new file mode 100644 index 0000000..3f4e66a --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultIdentity.java @@ -0,0 +1,303 @@ +/* + * Sone - DefaultIdentity.java - Copyright © 2010 David Roden + * + * This 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.freenet.wot; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.pterodactylus.sone.freenet.plugin.PluginException; +import net.pterodactylus.util.cache.CacheException; +import net.pterodactylus.util.cache.CacheItem; +import net.pterodactylus.util.cache.DefaultCacheItem; +import net.pterodactylus.util.cache.MemoryCache; +import net.pterodactylus.util.cache.ValueRetriever; +import net.pterodactylus.util.cache.WritableCache; +import net.pterodactylus.util.collection.TimedMap; +import net.pterodactylus.util.logging.Logging; + +/** + * A Web of Trust identity. + * + * @author David ‘Bombe’ Roden + */ +public class DefaultIdentity implements Identity { + + /** The logger. */ + private static final Logger logger = Logging.getLogger(DefaultIdentity.class); + + /** The web of trust connector. */ + private final WebOfTrustConnector webOfTrustConnector; + + /** The ID of the identity. */ + private final String id; + + /** The nickname of the identity. */ + private final String nickname; + + /** The request URI of the identity. */ + private final String requestUri; + + /** The contexts of the identity. */ + private final Set contexts = Collections.synchronizedSet(new HashSet()); + + /** The properties of the identity. */ + private final Map properties = Collections.synchronizedMap(new HashMap()); + + /** Cached trust. */ + private final WritableCache trustCache = new MemoryCache(new ValueRetriever() { + + @Override + @SuppressWarnings("synthetic-access") + public CacheItem retrieve(OwnIdentity ownIdentity) throws CacheException { + try { + return new DefaultCacheItem(webOfTrustConnector.getTrust(ownIdentity, DefaultIdentity.this)); + } catch (PluginException pe1) { + throw new CacheException("Could not retrieve trust for OwnIdentity: " + ownIdentity, pe1); + } + } + + }, new TimedMap>(60000)); + + /** + * Creates a new identity. + * + * @param webOfTrustConnector + * The web of trust connector + * @param id + * The ID of the identity + * @param nickname + * The nickname of the identity + * @param requestUri + * The request URI of the identity + */ + public DefaultIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri) { + this.webOfTrustConnector = webOfTrustConnector; + this.id = id; + this.nickname = nickname; + this.requestUri = requestUri; + } + + // + // ACCESSORS + // + + /** + * {@inheritDoc} + */ + @Override + public String getId() { + return id; + } + + /** + * {@inheritDoc} + */ + @Override + public String getNickname() { + return nickname; + } + + /** + * {@inheritDoc} + */ + @Override + public String getRequestUri() { + return requestUri; + } + + /** + * {@inheritDoc} + */ + @Override + public Set getContexts() { + return Collections.unmodifiableSet(contexts); + } + + /** + * Sets the contexts of this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param contexts + * The contexts to set + */ + void setContextsPrivate(Set contexts) { + this.contexts.clear(); + this.contexts.addAll(contexts); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasContext(String context) { + return contexts.contains(context); + } + + /** + * Adds the given context to this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to add + */ + void addContextPrivate(String context) { + contexts.add(context); + } + + /** + * Removes the given context from this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to remove + */ + public void removeContextPrivate(String context) { + contexts.remove(context); + } + + /** + * {@inheritDoc} + */ + @Override + public Map getProperties() { + synchronized (properties) { + return Collections.unmodifiableMap(properties); + } + } + + /** + * Sets all properties of this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param properties + * The new properties of this identity + */ + void setPropertiesPrivate(Map properties) { + synchronized (this.properties) { + this.properties.clear(); + this.properties.putAll(properties); + } + } + + /** + * Sets the property with the given name to the given value. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param name + * The name of the property + * @param value + * The value of the property + */ + void setPropertyPrivate(String name, String value) { + synchronized (properties) { + properties.put(name, value); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String getProperty(String name) { + synchronized (properties) { + return properties.get(name); + } + } + + /** + * Removes the property with the given name. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param name + * The name of the property to remove + */ + void removePropertyPrivate(String name) { + synchronized (properties) { + properties.remove(name); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Trust getTrust(OwnIdentity ownIdentity) { + try { + return trustCache.get(ownIdentity); + } catch (CacheException ce1) { + logger.log(Level.WARNING, "Could not get trust for OwnIdentity: " + ownIdentity, ce1); + return null; + } + } + + /** + * Sets the trust received for this identity by the given own identity. + * + * @param ownIdentity + * The own identity that gives the trust + * @param trust + * The trust received for this identity + */ + void setTrustPrivate(OwnIdentity ownIdentity, Trust trust) { + trustCache.put(ownIdentity, trust); + } + + // + // OBJECT METHODS + // + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof DefaultIdentity)) { + return false; + } + DefaultIdentity identity = (DefaultIdentity) object; + return identity.id.equals(id); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return getClass().getSimpleName() + "[id=" + id + ",nickname=" + nickname + ",contexts=" + contexts + ",properties=" + properties + "]"; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java new file mode 100644 index 0000000..ab96756 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java @@ -0,0 +1,170 @@ +/* + * Sone - DefaultOwnIdentity.java - Copyright © 2010 David Roden + * + * This 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.freenet.wot; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import net.pterodactylus.util.validation.Validation; + +/** + * An own identity is an identity that the owner of the node has full control + * over. + * + * @author David ‘Bombe’ Roden + */ +public class DefaultOwnIdentity extends DefaultIdentity implements OwnIdentity { + + /** The identity manager. */ + private final WebOfTrustConnector webOfTrustConnector; + + /** The insert URI of the identity. */ + private final String insertUri; + + /** + * Creates a new own identity. + * + * @param webOfTrustConnector + * The identity manager + * @param id + * The ID of the identity + * @param nickname + * The nickname of the identity + * @param requestUri + * The request URI of the identity + * @param insertUri + * The insert URI of the identity + */ + public DefaultOwnIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri, String insertUri) { + super(webOfTrustConnector, id, nickname, requestUri); + this.webOfTrustConnector = webOfTrustConnector; + this.insertUri = insertUri; + } + + // + // ACCESSORS + // + + /** + * {@inheritDoc} + */ + @Override + public String getInsertUri() { + return insertUri; + } + + /** + * {@inheritDoc} + */ + @Override + public void addContext(String context) throws WebOfTrustException { + webOfTrustConnector.addContext(this, context); + addContextPrivate(context); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeContext(String context) throws WebOfTrustException { + webOfTrustConnector.removeContext(this, context); + removeContextPrivate(context); + } + + /** + * {@inheritDoc} + */ + @Override + public void setContexts(Set contexts) throws WebOfTrustException { + for (String context : getContexts()) { + if (!contexts.contains(context)) { + webOfTrustConnector.removeContext(this, context); + } + } + for (String context : contexts) { + if (!getContexts().contains(context)) { + webOfTrustConnector.addContext(this, context); + } + } + setContextsPrivate(contexts); + } + + /** + * {@inheritDoc} + */ + @Override + public void setProperty(String name, String value) throws WebOfTrustException { + webOfTrustConnector.setProperty(this, name, value); + setPropertyPrivate(name, value); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeProperty(String name) throws WebOfTrustException { + webOfTrustConnector.removeProperty(this, name); + removePropertyPrivate(name); + } + + /** + * {@inheritDoc} + */ + @Override + public void setProperties(Map properties) throws WebOfTrustException { + for (Entry oldProperty : getProperties().entrySet()) { + if (!properties.containsKey(oldProperty.getKey())) { + webOfTrustConnector.removeProperty(this, oldProperty.getKey()); + } else { + webOfTrustConnector.setProperty(this, oldProperty.getKey(), properties.get(oldProperty.getKey())); + } + } + for (Entry newProperty : properties.entrySet()) { + if (!getProperties().containsKey(newProperty.getKey())) { + webOfTrustConnector.setProperty(this, newProperty.getKey(), newProperty.getValue()); + } + } + setPropertiesPrivate(properties); + } + + /** + * {@inheritDoc} + */ + @Override + public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException { + Validation.begin().isNotNull("Trust Target", target).isNotNull("Trust Comment", comment).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check(); + webOfTrustConnector.setTrust(this, target, trustValue, comment); + if (target instanceof DefaultIdentity) { + ((DefaultIdentity) target).setTrustPrivate(this, new Trust(trustValue, trustValue, 0)); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void removeTrust(Identity target) throws WebOfTrustException { + Validation.begin().isNotNull("Trust Target", target).check(); + webOfTrustConnector.removeTrust(this, target); + if (target instanceof DefaultIdentity) { + ((DefaultIdentity) target).setTrustPrivate(this, new Trust(null, null, null)); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java index 5816b47..1cf1644 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Identity.java @@ -17,102 +17,45 @@ package net.pterodactylus.sone.freenet.wot; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; /** - * A Web of Trust identity. + * Interface for web of trust identities, defining all functions that can be + * performed on an identity. The identity is the main entry point for identity + * management. * * @author David ‘Bombe’ Roden */ -public class Identity { - - /** The ID of the identity. */ - private final String id; - - /** The nickname of the identity. */ - private final String nickname; - - /** The request URI of the identity. */ - private final String requestUri; - - /** The contexts of the identity. */ - private final Set contexts = Collections.synchronizedSet(new HashSet()); - - /** The properties of the identity. */ - private final Map properties = Collections.synchronizedMap(new HashMap()); - - /** - * Creates a new identity. - * - * @param id - * The ID of the identity - * @param nickname - * The nickname of the identity - * @param requestUri - * The request URI of the identity - */ - public Identity(String id, String nickname, String requestUri) { - this.id = id; - this.nickname = nickname; - this.requestUri = requestUri; - } - - // - // ACCESSORS - // +public interface Identity { /** * Returns the ID of the identity. * * @return The ID of the identity */ - public String getId() { - return id; - } + public String getId(); /** * Returns the nickname of the identity. * * @return The nickname of the identity */ - public String getNickname() { - return nickname; - } + public String getNickname(); /** * Returns the request URI of the identity. * * @return The request URI of the identity */ - public String getRequestUri() { - return requestUri; - } + public String getRequestUri(); /** * Returns all contexts of this identity. * * @return All contexts of this identity */ - public Set getContexts() { - return Collections.unmodifiableSet(contexts); - } - - /** - * Sets all contexts of this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param contexts - * All contexts of the identity - */ - void setContexts(Set contexts) { - this.contexts.clear(); - this.contexts.addAll(contexts); - } + public Set getContexts(); /** * Returns whether this identity has the given context. @@ -122,75 +65,14 @@ public class Identity { * @return {@code true} if this identity has the given context, * {@code false} otherwise */ - public boolean hasContext(String context) { - return contexts.contains(context); - } - - /** - * Adds the given context to this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param context - * The context to add - */ - void addContext(String context) { - contexts.add(context); - } - - /** - * Removes the given context from this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param context - * The context to remove - */ - void removeContext(String context) { - contexts.remove(context); - } + public boolean hasContext(String context); /** * Returns all properties of this identity. * * @return All properties of this identity */ - public Map getProperties() { - synchronized (properties) { - return Collections.unmodifiableMap(properties); - } - } - - /** - * Sets all properties of this identity. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param properties - * The new properties of this identity - */ - void setProperties(Map properties) { - synchronized (this.properties) { - this.properties.clear(); - this.properties.putAll(properties); - } - } - - /** - * Sets the property with the given name to the given value. - *

- * This method is only called by the {@link IdentityManager}. - * - * @param name - * The name of the property - * @param value - * The value of the property - */ - void setProperty(String name, String value) { - synchronized (properties) { - properties.put(name, value); - } - } + public Map getProperties(); /** * Returns the value of the property with the given name. @@ -199,56 +81,19 @@ public class Identity { * The name of the property * @return The value of the property */ - public String getProperty(String name) { - synchronized (properties) { - return properties.get(name); - } - } + public String getProperty(String name); /** - * Removes the property with the given name. - *

- * This method is only called by the {@link IdentityManager}. + * Retrieves the trust that this identity receives from the given own + * identity. If this identity is not in the own identity’s trust tree, a + * {@link Trust} is returned that has all its elements set to {@code null}. + * If the trust can not be retrieved, {@code null} is returned. * - * @param name - * The name of the property to remove - */ - void removeProperty(String name) { - synchronized (properties) { - properties.remove(name); - } - } - - // - // OBJECT METHODS - // - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return id.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object object) { - if (!(object instanceof Identity)) { - return false; - } - Identity identity = (Identity) object; - return identity.id.equals(id); - } - - /** - * {@inheritDoc} + * @param ownIdentity + * The own identity to get the trust for + * @return The trust assigned to this identity, or {@code null} if the trust + * could not be retrieved */ - @Override - public String toString() { - return getClass().getSimpleName() + "[id=" + id + ",nickname=" + nickname + ",contexts=" + contexts + ",properties=" + properties + "]"; - } + public Trust getTrust(OwnIdentity ownIdentity); } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java index 64ea61f..3721f49 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListener.java @@ -47,25 +47,31 @@ public interface IdentityListener extends EventListener { /** * Notifies a listener that a new identity was discovered. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The new identity */ - public void identityAdded(Identity identity); + public void identityAdded(OwnIdentity ownIdentity, Identity identity); /** * Notifies a listener that some properties of the identity have changed. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The updated identity */ - public void identityUpdated(Identity identity); + public void identityUpdated(OwnIdentity ownIdentity, Identity identity); /** * Notifies a listener that an identity has gone away. * + * @param ownIdentity + * The own identity at the root of the trust tree * @param identity * The disappeared identity */ - public void identityRemoved(Identity identity); + public void identityRemoved(OwnIdentity ownIdentity, Identity identity); } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java index c08fd16..c6ea783 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/IdentityListenerManager.java @@ -68,39 +68,45 @@ public class IdentityListenerManager extends AbstractListenerManager oldIdentities = Collections.emptyMap(); + Map> oldIdentities = Collections.emptyMap(); while (!shouldStop()) { - Map currentIdentities = new HashMap(); + Map> currentIdentities = new HashMap>(); Map currentOwnIdentities = new HashMap(); - /* get all identities with the wanted context from WoT. */ - Set ownIdentities; try { - ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); + /* get all identities with the wanted context from WoT. */ + Set ownIdentities = webOfTrustConnector.loadAllOwnIdentities(); /* check for changes. */ for (OwnIdentity ownIdentity : ownIdentities) { @@ -271,76 +191,80 @@ public class IdentityManager extends AbstractService { checkOwnIdentities(currentOwnIdentities); /* now filter for context and get all identities. */ - currentOwnIdentities.clear(); for (OwnIdentity ownIdentity : ownIdentities) { if ((context != null) && !ownIdentity.hasContext(context)) { continue; } - currentOwnIdentities.put(ownIdentity.getId(), ownIdentity); - for (Identity identity : webOfTrustConnector.loadTrustedIdentities(ownIdentity, context)) { - currentIdentities.put(identity.getId(), identity); - } - } - /* find removed identities. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - identityListenerManager.fireIdentityRemoved(oldIdentity); + Set trustedIdentities = webOfTrustConnector.loadTrustedIdentities(ownIdentity, context); + Map identities = new HashMap(); + currentIdentities.put(ownIdentity, identities); + for (Identity identity : trustedIdentities) { + identities.put(identity.getId(), identity); } - } - /* find new identities. */ - for (Identity currentIdentity : currentIdentities.values()) { - if (!oldIdentities.containsKey(currentIdentity.getId())) { - identityListenerManager.fireIdentityAdded(currentIdentity); + /* find new identities. */ + for (Identity currentIdentity : currentIdentities.get(ownIdentity).values()) { + if (!oldIdentities.containsKey(ownIdentity) || !oldIdentities.get(ownIdentity).containsKey(currentIdentity.getId())) { + identityListenerManager.fireIdentityAdded(ownIdentity, currentIdentity); + } } - } - /* check for changes in the contexts. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - continue; - } - Identity newIdentity = currentIdentities.get(oldIdentity.getId()); - Set oldContexts = oldIdentity.getContexts(); - Set newContexts = newIdentity.getContexts(); - if (oldContexts.size() != newContexts.size()) { - identityListenerManager.fireIdentityUpdated(newIdentity); - continue; - } - for (String oldContext : oldContexts) { - if (!newContexts.contains(oldContext)) { - identityListenerManager.fireIdentityUpdated(newIdentity); - break; + /* find removed identities. */ + if (oldIdentities.containsKey(ownIdentity)) { + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + identityListenerManager.fireIdentityRemoved(ownIdentity, oldIdentity); + } } - } - } - /* check for changes in the properties. */ - for (Identity oldIdentity : oldIdentities.values()) { - if (!currentIdentities.containsKey(oldIdentity.getId())) { - continue; - } - Identity newIdentity = currentIdentities.get(oldIdentity.getId()); - Map oldProperties = oldIdentity.getProperties(); - Map newProperties = newIdentity.getProperties(); - if (oldProperties.size() != newProperties.size()) { - identityListenerManager.fireIdentityUpdated(newIdentity); - continue; - } - for (Entry oldProperty : oldProperties.entrySet()) { - if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) { - identityListenerManager.fireIdentityUpdated(newIdentity); - break; + /* check for changes in the contexts. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Set oldContexts = oldIdentity.getContexts(); + Set newContexts = newIdentity.getContexts(); + if (oldContexts.size() != newContexts.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (String oldContext : oldContexts) { + if (!newContexts.contains(oldContext)) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } + } + + /* check for changes in the properties. */ + for (Identity oldIdentity : oldIdentities.get(ownIdentity).values()) { + if (!currentIdentities.get(ownIdentity).containsKey(oldIdentity.getId())) { + continue; + } + Identity newIdentity = currentIdentities.get(ownIdentity).get(oldIdentity.getId()); + Map oldProperties = oldIdentity.getProperties(); + Map newProperties = newIdentity.getProperties(); + if (oldProperties.size() != newProperties.size()) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + continue; + } + for (Entry oldProperty : oldProperties.entrySet()) { + if (!newProperties.containsKey(oldProperty.getKey()) || !newProperties.get(oldProperty.getKey()).equals(oldProperty.getValue())) { + identityListenerManager.fireIdentityUpdated(ownIdentity, newIdentity); + break; + } + } } } - } - /* remember the current set of identities. */ - oldIdentities = currentIdentities; + /* remember the current set of identities. */ + oldIdentities = currentIdentities; + } - } catch (PluginException pe1) { - logger.log(Level.WARNING, "WoT has disappeared!", pe1); + } catch (WebOfTrustException wote1) { + logger.log(Level.WARNING, "WoT has disappeared!", wote1); } /* wait a minute before checking again. */ diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java index d9ec160..68a10f4 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/OwnIdentity.java @@ -17,45 +17,119 @@ package net.pterodactylus.sone.freenet.wot; +import java.util.Map; +import java.util.Set; + /** - * An own identity is an identity that the owner of the node has full control - * over. + * Defines a local identity, an own identity. * * @author David ‘Bombe’ Roden */ -public class OwnIdentity extends Identity { +public interface OwnIdentity extends Identity { + + /** + * Returns the insert URI of the identity. + * + * @return The insert URI of the identity + */ + public String getInsertUri(); - /** The insert URI of the identity. */ - private final String insertUri; + /** + * Adds the given context to this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to add + * @throws WebOfTrustException + * if an error occurs + */ + public void addContext(String context) throws WebOfTrustException; /** - * Creates a new own identity. + * Sets all contexts of this identity. + *

+ * This method is only called by the {@link IdentityManager}. * - * @param id - * The ID of the identity - * @param nickname - * The nickname of the identity - * @param requestUri - * The request URI of the identity - * @param insertUri - * The insert URI of the identity + * @param contexts + * All contexts of the identity + * @throws WebOfTrustException + * if an error occurs */ - public OwnIdentity(String id, String nickname, String requestUri, String insertUri) { - super(id, nickname, requestUri); - this.insertUri = insertUri; - } + public void setContexts(Set contexts) throws WebOfTrustException; - // - // ACCESSORS - // + /** + * Removes the given context from this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param context + * The context to remove + * @throws WebOfTrustException + * if an error occurs + */ + public void removeContext(String context) throws WebOfTrustException; /** - * Returns the insert URI of the identity. + * Sets the property with the given name to the given value. + *

+ * This method is only called by the {@link IdentityManager}. * - * @return The insert URI of the identity + * @param name + * The name of the property + * @param value + * The value of the property + * @throws WebOfTrustException + * if an error occurs + */ + public void setProperty(String name, String value) throws WebOfTrustException; + + /** + * Sets all properties of this identity. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param properties + * The new properties of this identity + * @throws WebOfTrustException + * if an error occurs + */ + public void setProperties(Map properties) throws WebOfTrustException; + + /** + * Removes the property with the given name. + *

+ * This method is only called by the {@link IdentityManager}. + * + * @param name + * The name of the property to remove + * @throws WebOfTrustException + * if an error occurs + */ + public void removeProperty(String name) throws WebOfTrustException; + + /** + * Sets the trust for the given target identity. + * + * @param target + * The target to set the trust for + * @param trustValue + * The new trust value (from {@code -100} or {@code 100}) + * @param comment + * The comment for the trust assignment + * @throws WebOfTrustException + * if an error occurs + */ + public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException; + + /** + * Removes any trust assignment for the given target identity. + * + * @param target + * The targe to remove the trust assignment for + * @throws WebOfTrustException + * if an error occurs */ - public String getInsertUri() { - return insertUri; - } + public void removeTrust(Identity target) throws WebOfTrustException; } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java deleted file mode 100644 index 561f092..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginConnector.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Sone - PluginConnector.java - Copyright © 2010 David Roden - * - * This 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.freenet.wot; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import net.pterodactylus.util.collection.Pair; -import freenet.pluginmanager.FredPluginTalker; -import freenet.pluginmanager.PluginNotFoundException; -import freenet.pluginmanager.PluginRespirator; -import freenet.pluginmanager.PluginTalker; -import freenet.support.SimpleFieldSet; -import freenet.support.api.Bucket; - -/** - * Interface for talking to other plugins. Other plugins are identified by their - * name and a unique connection identifier. - * - * @author David ‘Bombe’ Roden - */ -public class PluginConnector implements FredPluginTalker { - - /** The plugin respirator. */ - private final PluginRespirator pluginRespirator; - - /** Connector listener managers for all plugin connections. */ - private final Map, ConnectorListenerManager> connectorListenerManagers = Collections.synchronizedMap(new HashMap, ConnectorListenerManager>()); - - /** - * Creates a new plugin connector. - * - * @param pluginRespirator - * The plugin respirator - */ - public PluginConnector(PluginRespirator pluginRespirator) { - this.pluginRespirator = pluginRespirator; - } - - // - // LISTENER MANAGEMENT - // - - /** - * Adds a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to add - */ - public void addConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).addListener(connectorListener); - } - - /** - * Removes a connection listener for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param connectorListener - * The listener to remove - */ - public void removeConnectorListener(String pluginName, String identifier, ConnectorListener connectorListener) { - getConnectorListenerManager(pluginName, identifier).removeListener(connectorListener); - } - - // - // ACTIONS - // - - /** - * Sends a request to the given plugin. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param fields - * The fields of the message - * @throws PluginException - * if the plugin can not be found - */ - public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields) throws PluginException { - sendRequest(pluginName, identifier, fields, null); - } - - /** - * Sends a request to the given plugin. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param fields - * The fields of the message - * @param data - * The payload of the message (may be null) - * @throws PluginException - * if the plugin can not be found - */ - public void sendRequest(String pluginName, String identifier, SimpleFieldSet fields, Bucket data) throws PluginException { - getPluginTalker(pluginName, identifier).send(fields, data); - } - - // - // PRIVATE METHODS - // - - /** - * Returns the connection listener manager for the given plugin connection, - * creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @return The connection listener manager - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier) { - return getConnectorListenerManager(pluginName, identifier, true); - } - - /** - * Returns the connection listener manager for the given plugin connection, - * optionally creating a new one if none does exist yet. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @param create - * {@code true} to create a new manager if there is none, - * {@code false} to return {@code null} in that case - * @return The connection listener manager, or {@code null} if none existed - * and {@code create} is {@code false} - */ - private ConnectorListenerManager getConnectorListenerManager(String pluginName, String identifier, boolean create) { - ConnectorListenerManager connectorListenerManager = connectorListenerManagers.get(new Pair(pluginName, identifier)); - if (create && (connectorListenerManager == null)) { - connectorListenerManager = new ConnectorListenerManager(this); - connectorListenerManagers.put(new Pair(pluginName, identifier), connectorListenerManager); - } - return connectorListenerManager; - } - - /** - * Returns the plugin talker for the given plugin connection. - * - * @param pluginName - * The name of the plugin - * @param identifier - * The identifier of the connection - * @return The plugin talker - * @throws PluginException - * if the plugin can not be found - */ - private PluginTalker getPluginTalker(String pluginName, String identifier) throws PluginException { - try { - return pluginRespirator.getPluginTalker(this, pluginName, identifier); - } catch (PluginNotFoundException pnfe1) { - throw new PluginException(pnfe1); - } - } - - // - // INTERFACE FredPluginTalker - // - - /** - * {@inheritDoc} - */ - @Override - public void onReply(String pluginName, String identifier, SimpleFieldSet params, Bucket data) { - ConnectorListenerManager connectorListenerManager = getConnectorListenerManager(pluginName, identifier, false); - if (connectorListenerManager == null) { - /* we don’t care about events for this plugin. */ - return; - } - connectorListenerManager.fireReceivedReply(params, data); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java b/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java deleted file mode 100644 index 36cf49a..0000000 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/PluginException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Sone - PluginException.java - Copyright © 2010 David Roden - * - * This 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.freenet.wot; - -/** - * Exception that signals an error when communicating with a plugin. - * - * @author David ‘Bombe’ Roden - */ -public class PluginException extends Exception { - - /** - * Creates a new plugin exception. - */ - public PluginException() { - super(); - } - - /** - * Creates a new plugin exception. - * - * @param message - * The message of the exception - */ - public PluginException(String message) { - super(message); - } - - /** - * Creates a new plugin exception. - * - * @param cause - * The cause of the exception - */ - public PluginException(Throwable cause) { - super(cause); - } - - /** - * Creates a new plugin exception. - * - * @param message - * The message of the exception - * @param cause - * The cause of the exception - */ - public PluginException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java new file mode 100644 index 0000000..975dd3f --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/Trust.java @@ -0,0 +1,82 @@ +/* + * Sone - Trust.java - Copyright © 2010 David Roden + * + * This 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.freenet.wot; + +/** + * Container class for trust in the web of trust. + * + * @author David ‘Bombe’ Roden + */ +public class Trust { + + /** Explicitely assigned trust. */ + private final Integer explicit; + + /** Implicitely calculated trust. */ + private final Integer implicit; + + /** The distance from the owner of the trust tree. */ + private final Integer distance; + + /** + * Creates a new trust container. + * + * @param explicit + * The explicit trust + * @param implicit + * The implicit trust + * @param distance + * The distance + */ + public Trust(Integer explicit, Integer implicit, Integer distance) { + this.explicit = explicit; + this.implicit = implicit; + this.distance = distance; + } + + /** + * Returns the trust explicitely assigned to an identity. + * + * @return The explicitely assigned trust, or {@code null} if the identity + * is not in the own identity’s trust tree + */ + public Integer getExplicit() { + return explicit; + } + + /** + * Returns the implicitely assigned trust, or the calculated trust. + * + * @return The calculated trust, or {@code null} if the identity is not in + * the own identity’s trust tree + */ + public Integer getImplicit() { + return implicit; + } + + /** + * Returns the distance of the trusted identity from the trusting identity. + * + * @return The distance from the own identity, or {@code null} if the + * identity is not in the own identity’s trust tree + */ + public Integer getDistance() { + return distance; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index becb178..b6d68d3 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -17,7 +17,6 @@ package net.pterodactylus.sone.freenet.wot; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -25,6 +24,9 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import net.pterodactylus.sone.freenet.plugin.ConnectorListener; +import net.pterodactylus.sone.freenet.plugin.PluginConnector; +import net.pterodactylus.sone.freenet.plugin.PluginException; import net.pterodactylus.util.logging.Logging; import freenet.support.SimpleFieldSet; import freenet.support.api.Bucket; @@ -45,8 +47,8 @@ public class WebOfTrustConnector implements ConnectorListener { /** A random connection identifier. */ private static final String PLUGIN_CONNECTION_IDENTIFIER = "Sone-WoT-Connector-" + Math.abs(Math.random()); - /** The current replies that we wait for. */ - private final Map replies = Collections.synchronizedMap(new HashMap()); + /** The current reply. */ + private Reply reply; /** The plugin connector. */ private final PluginConnector pluginConnector; @@ -71,11 +73,11 @@ public class WebOfTrustConnector implements ConnectorListener { * Loads all own identities from the Web of Trust plugin. * * @return All own identity - * @throws PluginException + * @throws WebOfTrustException * if the own identities can not be loaded */ - public Set loadAllOwnIdentities() throws PluginException { - Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetOwnIdentities").get(), "OwnIdentities"); + public Set loadAllOwnIdentities() throws WebOfTrustException { + Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetOwnIdentities").get()); SimpleFieldSet fields = reply.getFields(); int ownIdentityCounter = -1; Set ownIdentities = new HashSet(); @@ -87,9 +89,9 @@ public class WebOfTrustConnector implements ConnectorListener { String requestUri = fields.get("RequestURI" + ownIdentityCounter); String insertUri = fields.get("InsertURI" + ownIdentityCounter); String nickname = fields.get("Nickname" + ownIdentityCounter); - OwnIdentity ownIdentity = new OwnIdentity(id, nickname, requestUri, insertUri); - ownIdentity.setContexts(parseContexts("Contexts" + ownIdentityCounter + ".", fields)); - ownIdentity.setProperties(parseProperties("Properties" + ownIdentityCounter + ".", fields)); + DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(this, id, nickname, requestUri, insertUri); + ownIdentity.setContextsPrivate(parseContexts("Contexts" + ownIdentityCounter + ".", fields)); + ownIdentity.setPropertiesPrivate(parseProperties("Properties" + ownIdentityCounter + ".", fields)); ownIdentities.add(ownIdentity); } return ownIdentities; @@ -122,7 +124,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public Set loadTrustedIdentities(OwnIdentity ownIdentity, String context) throws PluginException { - Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("TreeOwner", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get(), "Identities"); + Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("TreeOwner", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get()); SimpleFieldSet fields = reply.getFields(); Set identities = new HashSet(); int identityCounter = -1; @@ -133,9 +135,9 @@ public class WebOfTrustConnector implements ConnectorListener { } String nickname = fields.get("Nickname" + identityCounter); String requestUri = fields.get("RequestURI" + identityCounter); - Identity identity = new Identity(id, nickname, requestUri); - identity.setContexts(parseContexts("Contexts" + identityCounter + ".", fields)); - identity.setProperties(parseProperties("Properties" + identityCounter + ".", fields)); + DefaultIdentity identity = new DefaultIdentity(this, id, nickname, requestUri); + identity.setContextsPrivate(parseContexts("Contexts" + identityCounter + ".", fields)); + identity.setPropertiesPrivate(parseProperties("Properties" + identityCounter + ".", fields)); identities.add(identity); } return identities; @@ -152,7 +154,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public void addContext(OwnIdentity ownIdentity, String context) throws PluginException { - performRequest(SimpleFieldSetConstructor.create().put("Message", "AddContext").put("Identity", ownIdentity.getId()).put("Context", context).get(), "ContextAdded"); + performRequest(SimpleFieldSetConstructor.create().put("Message", "AddContext").put("Identity", ownIdentity.getId()).put("Context", context).get()); } /** @@ -166,7 +168,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public void removeContext(OwnIdentity ownIdentity, String context) throws PluginException { - performRequest(SimpleFieldSetConstructor.create().put("Message", "RemoveContext").put("Identity", ownIdentity.getId()).put("Context", context).get(), "ContextRemoved"); + performRequest(SimpleFieldSetConstructor.create().put("Message", "RemoveContext").put("Identity", ownIdentity.getId()).put("Context", context).get()); } /** @@ -181,7 +183,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public String getProperty(Identity identity, String name) throws PluginException { - Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetProperty").put("Identity", identity.getId()).put("Property", name).get(), "PropertyValue"); + Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetProperty").put("Identity", identity.getId()).put("Property", name).get()); return reply.getFields().get("Property"); } @@ -198,7 +200,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public void setProperty(OwnIdentity ownIdentity, String name, String value) throws PluginException { - performRequest(SimpleFieldSetConstructor.create().put("Message", "SetProperty").put("Identity", ownIdentity.getId()).put("Property", name).put("Value", value).get(), "PropertyAdded"); + performRequest(SimpleFieldSetConstructor.create().put("Message", "SetProperty").put("Identity", ownIdentity.getId()).put("Property", name).put("Value", value).get()); } /** @@ -212,7 +214,74 @@ public class WebOfTrustConnector implements ConnectorListener { * if an error occured talking to the Web of Trust plugin */ public void removeProperty(OwnIdentity ownIdentity, String name) throws PluginException { - performRequest(SimpleFieldSetConstructor.create().put("Message", "RemoveProperty").put("Identity", ownIdentity.getId()).put("Property", name).get(), "PropertyRemoved"); + performRequest(SimpleFieldSetConstructor.create().put("Message", "RemoveProperty").put("Identity", ownIdentity.getId()).put("Property", name).get()); + } + + /** + * Returns the trust for the given identity assigned to it by the given own + * identity. + * + * @param ownIdentity + * The own identity + * @param identity + * The identity to get the trust for + * @return The trust for the given identity + * @throws PluginException + * if an error occured talking to the Web of Trust plugin + */ + public Trust getTrust(OwnIdentity ownIdentity, Identity identity) throws PluginException { + Reply getTrustReply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentity").put("TreeOwner", ownIdentity.getId()).put("Identity", identity.getId()).get()); + String trust = getTrustReply.getFields().get("Trust"); + String score = getTrustReply.getFields().get("Score"); + String rank = getTrustReply.getFields().get("Rank"); + Integer explicit = null; + Integer implicit = null; + Integer distance = null; + try { + explicit = Integer.valueOf(trust); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + try { + implicit = Integer.valueOf(score); + distance = Integer.valueOf(rank); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + return new Trust(explicit, implicit, distance); + } + + /** + * Sets the trust for the given identity. + * + * @param ownIdentity + * The trusting identity + * @param identity + * The trusted identity + * @param trust + * The amount of trust (-100 thru 100) + * @param comment + * The comment or explanation of the trust value + * @throws PluginException + * if an error occured talking to the Web of Trust plugin + */ + public void setTrust(OwnIdentity ownIdentity, Identity identity, int trust, String comment) throws PluginException { + performRequest(SimpleFieldSetConstructor.create().put("Message", "SetTrust").put("Truster", ownIdentity.getId()).put("Trustee", identity.getId()).put("Value", String.valueOf(trust)).put("Comment", comment).get()); + } + + /** + * Removes any trust assignment of the given own identity for the given + * identity. + * + * @param ownIdentity + * The own identity + * @param identity + * The identity to remove all trust for + * @throws WebOfTrustException + * if an error occurs + */ + public void removeTrust(OwnIdentity ownIdentity, Identity identity) throws WebOfTrustException { + performRequest(SimpleFieldSetConstructor.create().put("Message", "RemoveTrust").put("Truster", ownIdentity.getId()).put("Trustee", identity.getId()).get()); } /** @@ -223,7 +292,7 @@ public class WebOfTrustConnector implements ConnectorListener { * if the plugin is not loaded */ public void ping() throws PluginException { - performRequest(SimpleFieldSetConstructor.create().put("Message", "Ping").get(), "Pong"); + performRequest(SimpleFieldSetConstructor.create().put("Message", "Ping").get()); } // @@ -281,14 +350,12 @@ public class WebOfTrustConnector implements ConnectorListener { * * @param fields * The fields of the message - * @param targetMessages - * The messages of the reply to wait for * @return The reply message * @throws PluginException * if the request could not be sent */ - private Reply performRequest(SimpleFieldSet fields, String... targetMessages) throws PluginException { - return performRequest(fields, null, targetMessages); + private Reply performRequest(SimpleFieldSet fields) throws PluginException { + return performRequest(fields, null); } /** @@ -299,43 +366,24 @@ public class WebOfTrustConnector implements ConnectorListener { * The fields of the message * @param data * The payload of the message - * @param targetMessages - * The messages of the reply to wait for * @return The reply message * @throws PluginException * if the request could not be sent */ - private Reply performRequest(SimpleFieldSet fields, Bucket data, String... targetMessages) throws PluginException { - @SuppressWarnings("synthetic-access") - Reply reply = new Reply(); - for (String targetMessage : targetMessages) { - replies.put(targetMessage, reply); - } - replies.put("Error", reply); + private synchronized Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException { + reply = new Reply(); + logger.log(Level.FINE, "Sending FCP Request: " + fields.get("Message")); synchronized (reply) { pluginConnector.sendRequest(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, fields, data); try { - long now = System.currentTimeMillis(); - while ((reply.getFields() == null) && ((System.currentTimeMillis() - now) < 60000)) { - reply.wait(60000 - (System.currentTimeMillis() - now)); - } - if (reply.getFields() == null) { - for (String targetMessage : targetMessages) { - replies.remove(targetMessage); - } - replies.remove("Error"); - throw new PluginException("Timeout waiting for " + targetMessages[0] + "!"); - } + reply.wait(); } catch (InterruptedException ie1) { - logger.log(Level.WARNING, "Got interrupted while waiting for reply on " + targetMessages[0] + ".", ie1); + logger.log(Level.WARNING, "Got interrupted while waiting for reply on " + fields.get("Message") + ".", ie1); } } - for (String targetMessage : targetMessages) { - replies.remove(targetMessage); - } - replies.remove("Error"); - if ((reply.getFields() != null) && reply.getFields().get("Message").equals("Error")) { - throw new PluginException("Could not perform request for " + targetMessages[0]); + logger.log(Level.FINEST, "Received FCP Response for %s: %s", new Object[] { fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null }); + if ((reply.getFields() == null) || "Error".equals(reply.getFields().get("Message"))) { + throw new PluginException("Could not perform request for " + fields.get("Message")); } return reply; } @@ -351,11 +399,6 @@ public class WebOfTrustConnector implements ConnectorListener { public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) { String messageName = fields.get("Message"); logger.log(Level.FINEST, "Received Reply from Plugin: " + messageName); - Reply reply = replies.remove(messageName); - if (reply == null) { - logger.log(Level.FINE, "Not waiting for a “%s” message.", messageName); - return; - } synchronized (reply) { reply.setFields(fields); reply.setData(data); @@ -376,6 +419,11 @@ public class WebOfTrustConnector implements ConnectorListener { /** The payload of the reply. */ private Bucket data; + /** Empty constructor. */ + public Reply() { + /* do nothing. */ + } + /** * Returns the fields of the reply. * diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java new file mode 100644 index 0000000..f59b2a3 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustException.java @@ -0,0 +1,67 @@ +/* + * Sone - WebOfTrustException.java - Copyright © 2010 David Roden + * + * This 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.freenet.wot; + +/** + * Exception that signals an error processing web of trust identities, mostly + * when communicating with the web of trust plugin. + * + * @author David ‘Bombe’ Roden + */ +public class WebOfTrustException extends Exception { + + /** + * Creates a new web of trust exception. + */ + public WebOfTrustException() { + super(); + } + + /** + * Creates a new web of trust exception. + * + * @param message + * The message of the exception + */ + public WebOfTrustException(String message) { + super(message); + } + + /** + * Creates a new web of trust exception. + * + * @param cause + * The cause of the exception + */ + public WebOfTrustException(Throwable cause) { + super(cause); + } + + /** + * Creates a new web of trust exception. + * + * @param message + * The message of the exception + * @param cause + * The cause of the exception + */ + public WebOfTrustException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index a0a22f9..64f84e2 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -25,8 +25,8 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.core.FreenetInterface; import net.pterodactylus.sone.freenet.PluginStoreConfigurationBackend; +import net.pterodactylus.sone.freenet.plugin.PluginConnector; import net.pterodactylus.sone.freenet.wot.IdentityManager; -import net.pterodactylus.sone.freenet.wot.PluginConnector; import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.util.config.Configuration; diff --git a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java index c9c5f48..0cb92ff 100644 --- a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java @@ -21,6 +21,7 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.core.Core.SoneStatus; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.util.template.Accessor; import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.ReflectionAccessor; @@ -89,6 +90,12 @@ public class SoneAccessor extends ReflectionAccessor { return core.isNewSone(sone); } else if (member.equals("locked")) { return core.isLocked(sone); + } else if (member.equals("trust")) { + Sone currentSone = (Sone) dataProvider.getData("currentSone"); + Trust trust = core.getTrust(currentSone, sone); + if (trust == null) { + return new Trust(null, null, null); + } } return super.get(dataProvider, object, member); } diff --git a/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java new file mode 100644 index 0000000..4dfd81e --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/template/TrustAccessor.java @@ -0,0 +1,54 @@ +/* + * Sone - TrustAccessor.java - Copyright © 2010 David Roden + * + * This 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.template; + +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.util.template.Accessor; +import net.pterodactylus.util.template.DataProvider; +import net.pterodactylus.util.template.ReflectionAccessor; + +/** + * {@link Accessor} implementation for {@link Trust} values, adding the + * following properties: + *

+ *
assigned
+ *
{@link Boolean} that indicates whether this trust relationship has an + * explicit value assigned to it.
+ *
+ * + * @author David ‘Bombe’ Roden + */ +public class TrustAccessor extends ReflectionAccessor { + + /** + * {@inheritDoc} + */ + @Override + public Object get(DataProvider dataProvider, Object object, String member) { + Trust trust = (Trust) object; + if ("assigned".equals(member)) { + return trust.getExplicit() != null; + } else if ("maximum".equals(member)) { + return ((trust.getExplicit() != null) && (trust.getExplicit() >= 100)) || ((trust.getImplicit() != null) && (trust.getImplicit() >= 100)); + } else if ("hasDistance".equals(member)) { + return (trust.getDistance() != null) && (trust.getDistance() != Integer.MAX_VALUE); + } + return super.get(dataProvider, object, member); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java index 04b5d37..46302b0 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java @@ -112,7 +112,6 @@ public class CreateSonePage extends SoneTemplatePage { return; } /* create Sone. */ - webInterface.getCore().getIdentityManager().addContext(selectedIdentity, "Sone"); Sone sone = webInterface.getCore().createSone(selectedIdentity); if (sone == null) { logger.log(Level.SEVERE, "Could not create Sone for OwnIdentity: %s", selectedIdentity); diff --git a/src/main/java/net/pterodactylus/sone/web/DistrustPage.java b/src/main/java/net/pterodactylus/sone/web/DistrustPage.java new file mode 100644 index 0000000..9cbbb55 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/DistrustPage.java @@ -0,0 +1,69 @@ +/* + * Sone - TrustPage.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.web; + +import net.pterodactylus.sone.core.Core; +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; + +/** + * Page that lets the user distrust another Sone. This will assign a + * configurable (negative) amount of trust to an identity. + * + * @see Core#distrustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class DistrustPage extends SoneTemplatePage { + + /** + * Creates a new “distrust Sone” page. + * + * @param template + * The template to render + * @param webInterface + * The Sone web interface + */ + public DistrustPage(Template template, WebInterface webInterface) { + super("distrust.html", template, "Page.Distrust.Title", webInterface, true); + } + + // + // SONETEMPLATEPAGE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); + if (request.getMethod() == Method.POST) { + String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256); + String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); + Sone currentSone = getCurrentSone(request.getToadletContext()); + Sone sone = webInterface.getCore().getSone(identity, false); + if (sone != null) { + webInterface.getCore().distrustSone(currentSone, sone); + } + throw new RedirectException(returnPath); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java index 63ed6a7..0739ae7 100644 --- a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java +++ b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java @@ -56,6 +56,15 @@ public class OptionsPage extends SoneTemplatePage { if (request.getMethod() == Method.POST) { Integer insertionDelay = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("insertion-delay", 16)); options.getIntegerOption("InsertionDelay").set(insertionDelay); + Integer positiveTrust = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("positive-trust", 3), options.getIntegerOption("PositiveTrust").getReal()); + options.getIntegerOption("PositiveTrust").set(positiveTrust); + Integer negativeTrust = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("negative-trust", 3), options.getIntegerOption("NegativeTrust").getReal()); + options.getIntegerOption("NegativeTrust").set(negativeTrust); + String trustComment = request.getHttpRequest().getPartAsStringFailsafe("trust-comment", 256); + if (trustComment.trim().length() == 0) { + trustComment = null; + } + options.getStringOption("TrustComment").set(trustComment); boolean soneRescueMode = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("sone-rescue-mode", 5)); options.getBooleanOption("SoneRescueMode").set(soneRescueMode); boolean clearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("clear-on-next-restart", 5)); @@ -66,6 +75,9 @@ public class OptionsPage extends SoneTemplatePage { throw new RedirectException(getPath()); } dataProvider.set("insertion-delay", options.getIntegerOption("InsertionDelay").get()); + dataProvider.set("positive-trust", options.getIntegerOption("PositiveTrust").get()); + dataProvider.set("negative-trust", options.getIntegerOption("NegativeTrust").get()); + dataProvider.set("trust-comment", options.getStringOption("TrustComment").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/TrustPage.java b/src/main/java/net/pterodactylus/sone/web/TrustPage.java new file mode 100644 index 0000000..85341ad --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/TrustPage.java @@ -0,0 +1,69 @@ +/* + * Sone - TrustPage.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.web; + +import net.pterodactylus.sone.core.Core; +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; + +/** + * Page that lets the user trust another Sone. This will assign a configurable + * amount of trust to an identity. + * + * @see Core#trustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class TrustPage extends SoneTemplatePage { + + /** + * Creates a new “trust Sone” page. + * + * @param template + * The template to render + * @param webInterface + * The Sone web interface + */ + public TrustPage(Template template, WebInterface webInterface) { + super("trust.html", template, "Page.Trust.Title", webInterface, true); + } + + // + // SONETEMPLATEPAGE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); + if (request.getMethod() == Method.POST) { + String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256); + String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); + Sone currentSone = getCurrentSone(request.getToadletContext()); + Sone sone = webInterface.getCore().getSone(identity, false); + if (sone != null) { + webInterface.getCore().trustSone(currentSone, sone); + } + throw new RedirectException(returnPath); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/UntrustPage.java b/src/main/java/net/pterodactylus/sone/web/UntrustPage.java new file mode 100644 index 0000000..cc9e26d --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/UntrustPage.java @@ -0,0 +1,69 @@ +/* + * Sone - TrustPage.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.web; + +import net.pterodactylus.sone.core.Core; +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; + +/** + * Page that lets the user untrust another Sone. This will remove all trust + * assignments for an identity. + * + * @see Core#untrustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class UntrustPage extends SoneTemplatePage { + + /** + * Creates a new “untrust Sone” page. + * + * @param template + * The template to render + * @param webInterface + * The Sone web interface + */ + public UntrustPage(Template template, WebInterface webInterface) { + super("untrust.html", template, "Page.Untrust.Title", webInterface, true); + } + + // + // SONETEMPLATEPAGE METHODS + // + + /** + * {@inheritDoc} + */ + @Override + protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException { + super.processTemplate(request, dataProvider); + if (request.getMethod() == Method.POST) { + String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256); + String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44); + Sone currentSone = getCurrentSone(request.getToadletContext()); + Sone sone = webInterface.getCore().getSone(identity, false); + if (sone != null) { + webInterface.getCore().untrustSone(currentSone, sone); + } + throw new RedirectException(returnPath); + } + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 250bff0..adcc17e 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +41,7 @@ import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.L10nFilter; import net.pterodactylus.sone.freenet.wot.Identity; +import net.pterodactylus.sone.freenet.wot.Trust; import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.notify.ListNotification; import net.pterodactylus.sone.template.CollectionAccessor; @@ -53,12 +55,14 @@ import net.pterodactylus.sone.template.ReplyAccessor; import net.pterodactylus.sone.template.RequestChangeFilter; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.template.SubstringFilter; +import net.pterodactylus.sone.template.TrustAccessor; import net.pterodactylus.sone.web.ajax.CreatePostAjaxPage; import net.pterodactylus.sone.web.ajax.CreateReplyAjaxPage; import net.pterodactylus.sone.web.ajax.DeletePostAjaxPage; import net.pterodactylus.sone.web.ajax.DeleteProfileFieldAjaxPage; import net.pterodactylus.sone.web.ajax.DeleteReplyAjaxPage; import net.pterodactylus.sone.web.ajax.DismissNotificationAjaxPage; +import net.pterodactylus.sone.web.ajax.DistrustAjaxPage; import net.pterodactylus.sone.web.ajax.EditProfileFieldAjaxPage; import net.pterodactylus.sone.web.ajax.FollowSoneAjaxPage; import net.pterodactylus.sone.web.ajax.GetLikesAjaxPage; @@ -71,9 +75,11 @@ import net.pterodactylus.sone.web.ajax.LockSoneAjaxPage; import net.pterodactylus.sone.web.ajax.MarkPostAsKnownPage; import net.pterodactylus.sone.web.ajax.MarkReplyAsKnownPage; import net.pterodactylus.sone.web.ajax.MoveProfileFieldAjaxPage; +import net.pterodactylus.sone.web.ajax.TrustAjaxPage; import net.pterodactylus.sone.web.ajax.UnfollowSoneAjaxPage; import net.pterodactylus.sone.web.ajax.UnlikeAjaxPage; import net.pterodactylus.sone.web.ajax.UnlockSoneAjaxPage; +import net.pterodactylus.sone.web.ajax.UntrustAjaxPage; import net.pterodactylus.sone.web.page.PageToadlet; import net.pterodactylus.sone.web.page.PageToadletFactory; import net.pterodactylus.sone.web.page.StaticPage; @@ -167,6 +173,7 @@ public class WebInterface implements CoreListener { templateFactory.addAccessor(Reply.class, new ReplyAccessor(getCore(), templateFactory)); templateFactory.addAccessor(Identity.class, new IdentityAccessor(getCore())); templateFactory.addAccessor(NotificationManager.class, new NotificationManagerAccessor()); + templateFactory.addAccessor(Trust.class, new TrustAccessor()); templateFactory.addFilter("date", new DateFilter()); templateFactory.addFilter("l10n", new L10nFilter(getL10n())); templateFactory.addFilter("substring", new SubstringFilter()); @@ -471,6 +478,7 @@ public class WebInterface implements CoreListener { * Register all toadlets. */ private void registerToadlets() { + Template emptyTemplate = templateFactory.createTemplate(new StringReader("")); Template loginTemplate = templateFactory.createTemplate(createReader("/templates/login.html")); Template indexTemplate = templateFactory.createTemplate(createReader("/templates/index.html")); Template knownSonesTemplate = templateFactory.createTemplate(createReader("/templates/knownSones.html")); @@ -482,18 +490,10 @@ public class WebInterface implements CoreListener { Template deleteProfileFieldTemplate = templateFactory.createTemplate(createReader("/templates/deleteProfileField.html")); Template viewSoneTemplate = templateFactory.createTemplate(createReader("/templates/viewSone.html")); Template viewPostTemplate = templateFactory.createTemplate(createReader("/templates/viewPost.html")); - Template likePostTemplate = templateFactory.createTemplate(createReader("/templates/like.html")); - Template unlikePostTemplate = templateFactory.createTemplate(createReader("/templates/unlike.html")); Template deletePostTemplate = templateFactory.createTemplate(createReader("/templates/deletePost.html")); Template deleteReplyTemplate = templateFactory.createTemplate(createReader("/templates/deleteReply.html")); - Template lockSoneTemplate = templateFactory.createTemplate(createReader("/templates/lockSone.html")); - Template unlockSoneTemplate = templateFactory.createTemplate(createReader("/templates/unlockSone.html")); - Template followSoneTemplate = templateFactory.createTemplate(createReader("/templates/followSone.html")); - Template unfollowSoneTemplate = templateFactory.createTemplate(createReader("/templates/unfollowSone.html")); Template deleteSoneTemplate = templateFactory.createTemplate(createReader("/templates/deleteSone.html")); Template noPermissionTemplate = templateFactory.createTemplate(createReader("/templates/noPermission.html")); - Template dismissNotificationTemplate = templateFactory.createTemplate(createReader("/templates/dismissNotification.html")); - Template logoutTemplate = templateFactory.createTemplate(createReader("/templates/logout.html")); Template optionsTemplate = templateFactory.createTemplate(createReader("/templates/options.html")); Template aboutTemplate = templateFactory.createTemplate(createReader("/templates/about.html")); Template invalidTemplate = templateFactory.createTemplate(createReader("/templates/invalid.html")); @@ -511,21 +511,24 @@ public class WebInterface implements CoreListener { pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyPage(createReplyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new ViewSonePage(viewSoneTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new ViewPostPage(viewPostTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LikePage(likePostTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlikePage(unlikePostTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new LikePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlikePage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DeletePostPage(deletePostTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteReplyPage(deleteReplyTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LockSonePage(lockSoneTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSonePage(unlockSoneTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSonePage(followSoneTemplate, this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSonePage(unfollowSoneTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new LockSonePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSonePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSonePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSonePage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustPage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustPage(emptyTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustPage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteSonePage(deleteSoneTemplate, this), "DeleteSone")); pageToadlets.add(pageToadletFactory.createPageToadlet(new LoginPage(loginTemplate, this), "Login")); - pageToadlets.add(pageToadletFactory.createPageToadlet(new LogoutPage(logoutTemplate, this), "Logout")); + pageToadlets.add(pageToadletFactory.createPageToadlet(new LogoutPage(emptyTemplate, this), "Logout")); pageToadlets.add(pageToadletFactory.createPageToadlet(new OptionsPage(optionsTemplate, this), "Options")); pageToadlets.add(pageToadletFactory.createPageToadlet(new AboutPage(aboutTemplate, this, SonePlugin.VERSION), "About")); pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("noPermission.html", noPermissionTemplate, "Page.NoPermission.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(dismissNotificationTemplate, this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("invalid.html", invalidTemplate, "Page.Invalid.Title", this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage("css/", "/static/css/", "text/css"))); pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage("javascript/", "/static/javascript/", "text/javascript"))); @@ -545,6 +548,9 @@ public class WebInterface implements CoreListener { pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlockSoneAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSoneAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSoneAjaxPage(this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustAjaxPage(this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustAjaxPage(this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new LikeAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new UnlikeAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetLikesAjaxPage(this))); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java new file mode 100644 index 0000000..1a6d28f --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java @@ -0,0 +1,66 @@ +/* + * Sone - TrustAjaxPage.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.web.ajax; + +import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.sone.web.WebInterface; +import net.pterodactylus.util.json.JsonObject; + +/** + * AJAX page that lets the user distrust a Sone. + * + * @see Core#distrustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class DistrustAjaxPage extends JsonPage { + + /** + * Creates a new “distrust Sone” AJAX handler. + * + * @param webInterface + * The Sone web interface + */ + public DistrustAjaxPage(WebInterface webInterface) { + super("distrustSone.ajax", webInterface); + } + + /** + * {@inheritDoc} + */ + @Override + protected JsonObject createJsonObject(Request request) { + Sone currentSone = getCurrentSone(request.getToadletContext(), false); + if (currentSone == null) { + return createErrorJsonObject("auth-required"); + } + String soneId = request.getHttpRequest().getParam("sone"); + Sone sone = webInterface.getCore().getSone(soneId, false); + if (sone == null) { + return createErrorJsonObject("invalid-sone-id"); + } + webInterface.getCore().distrustSone(currentSone, sone); + Trust trust = webInterface.getCore().getTrust(currentSone, sone); + if (trust == null) { + return createErrorJsonObject("wot-plugin"); + } + return createSuccessJsonObject().put("trustValue", trust.getExplicit()); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java new file mode 100644 index 0000000..d6e2750 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java @@ -0,0 +1,66 @@ +/* + * Sone - TrustAjaxPage.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.web.ajax; + +import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.sone.web.WebInterface; +import net.pterodactylus.util.json.JsonObject; + +/** + * AJAX page that lets the user trust a Sone. + * + * @see Core#trustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class TrustAjaxPage extends JsonPage { + + /** + * Creates a new “trust Sone” AJAX handler. + * + * @param webInterface + * The Sone web interface + */ + public TrustAjaxPage(WebInterface webInterface) { + super("trustSone.ajax", webInterface); + } + + /** + * {@inheritDoc} + */ + @Override + protected JsonObject createJsonObject(Request request) { + Sone currentSone = getCurrentSone(request.getToadletContext(), false); + if (currentSone == null) { + return createErrorJsonObject("auth-required"); + } + String soneId = request.getHttpRequest().getParam("sone"); + Sone sone = webInterface.getCore().getSone(soneId, false); + if (sone == null) { + return createErrorJsonObject("invalid-sone-id"); + } + webInterface.getCore().trustSone(currentSone, sone); + Trust trust = webInterface.getCore().getTrust(currentSone, sone); + if (trust == null) { + return createErrorJsonObject("wot-plugin"); + } + return createSuccessJsonObject().put("trustValue", trust.getExplicit()); + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java new file mode 100644 index 0000000..32c6229 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java @@ -0,0 +1,66 @@ +/* + * Sone - TrustAjaxPage.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.web.ajax; + +import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.data.Sone; +import net.pterodactylus.sone.freenet.wot.Trust; +import net.pterodactylus.sone.web.WebInterface; +import net.pterodactylus.util.json.JsonObject; + +/** + * AJAX page that lets the user untrust a Sone. + * + * @see Core#untrustSone(Sone, Sone) + * @author David ‘Bombe’ Roden + */ +public class UntrustAjaxPage extends JsonPage { + + /** + * Creates a new “untrust Sone” AJAX handler. + * + * @param webInterface + * The Sone web interface + */ + public UntrustAjaxPage(WebInterface webInterface) { + super("untrustSone.ajax", webInterface); + } + + /** + * {@inheritDoc} + */ + @Override + protected JsonObject createJsonObject(Request request) { + Sone currentSone = getCurrentSone(request.getToadletContext(), false); + if (currentSone == null) { + return createErrorJsonObject("auth-required"); + } + String soneId = request.getHttpRequest().getParam("sone"); + Sone sone = webInterface.getCore().getSone(soneId, false); + if (sone == null) { + return createErrorJsonObject("invalid-sone-id"); + } + webInterface.getCore().untrustSone(currentSone, sone); + Trust trust = webInterface.getCore().getTrust(currentSone, sone); + if (trust == null) { + return createErrorJsonObject("wot-plugin"); + } + return createSuccessJsonObject().put("trustValue", trust.getExplicit()); + } + +} diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index ccedff0..76d8941 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -27,6 +27,10 @@ Page.Options.Page.Title=Options Page.Options.Page.Description=These options influence the runtime behaviour of the Sone plugin. Page.Options.Section.RuntimeOptions.Title=Runtime Behaviour Page.Options.Option.InsertionDelay.Description=The number of seconds the Sone inserter waits after a modification of a Sone before it is being inserted. +Page.Options.Section.TrustOptions.Title=Trust Settings +Page.Options.Option.PositiveTrust.Description=The amount of positive trust you want to assign to other Sones by clicking the checkmark below a post or reply. +Page.Options.Option.NegativeTrust.Description=The amount of trust you want to assign to other Sones by clicking the red X below a post or reply. This value should be negative. +Page.Options.Option.TrustComment.Description=The comment that will be set in the web of trust for any trust you assign from Sone. Page.Options.Section.RescueOptions.Title=Rescue Settings Page.Options.Option.SoneRescueMode.Description=Try to rescue your Sones at the next start of the Sone plugin. This will read your all your old Sones from Freenet and ignore any disappearing postings and replies. You have to unlock your local Sones after they have been restored and you have to manually disable the rescue mode once you are satisfied with what has been restored! Page.Options.Section.Cleaning.Title=Clean Up @@ -147,6 +151,12 @@ Page.FollowSone.Title=Follow Sone - Sone Page.UnfollowSone.Title=Unfollow Sone - Sone +Page.Trust.Title=Trust Sone - Sone + +Page.Distrust.Title=Distrust Sone - Sone + +Page.Untrust.Title=Untrust Sone - Sone + Page.NoPermission.Title=Unauthorized Access - Sone Page.NoPermission.Page.Title=Unauthorized Access Page.NoPermission.Text.NoPermission=You tried to do something that you do not have sufficient authorization for. Please refrain from such actions in the future or we will be forced to take counter-measures! @@ -189,6 +199,10 @@ View.Post.Reply.DeleteLink=Delete View.Post.LikeLink=Like View.Post.UnlikeLink=Unlike +View.Trust.Tooltip.Trust=Trust this person +View.Trust.Tooltip.Distrust=Assign negative trust to this person +View.Trust.Tooltip.Untrust=Remove your trust assignment for this person + WebInterface.DefaultText.StatusUpdate=What’s on your mind? WebInterface.DefaultText.Message=Write a Message… WebInterface.DefaultText.Reply=Write a Reply… diff --git a/src/main/resources/static/css/sone.css b/src/main/resources/static/css/sone.css index f444cab..54cfb6e 100644 --- a/src/main/resources/static/css/sone.css +++ b/src/main/resources/static/css/sone.css @@ -1,7 +1,7 @@ /* Sone Main CSS File */ /* first, override some fproxy rules. */ -#sone .post .reply div,#sone .post .time,#sone .post .delete,#sone .post .show-reply-form, input[type=text], textarea { +#sone div, #sone span, #sone .post .time,#sone .post .delete,#sone .post .show-reply-form, input[type=text], textarea { font: inherit; } @@ -223,33 +223,52 @@ textarea { font-size: 85%; } +#sone .separator { + font: inherit; + color: rgb(28, 131, 191); +} + #sone .post .time { display: inline; color: #666; } -#sone .post .delete, #sone .post .likes, #sone .post .like, #sone .post .unlike { +#sone .post .delete, #sone .post .likes, #sone .post .like, #sone .post .unlike, #sone .post .trust, #sone .post .distrust, #sone .post .untrust { display: inline; font: inherit; + margin: 0px; } #sone .post .likes.hidden { display: none; } -#sone .post .like.hidden, #sone .post .unlike.hidden { +#sone .post .like.hidden, #sone .post .unlike.hidden, #sone .post .trust.hidden, #sone .post .distrust.hidden, #sone .post .untrust.hidden { display: none; } -#sone .post .delete button, #sone .post .like button, #sone .post .unlike button { +#sone .post .delete button, #sone .post .like button, #sone .post .unlike button, #sone .post .trust button, #sone .post .distrust button, #sone .post .untrust button { border: 0px; background: none; padding: 0px; color: rgb(28, 131, 191); font: inherit; + margin: 0px; +} + +#sone .post .trust button { + color: rgb(0, 128, 0); } -#sone .post .delete button:hover, #sone .post .like button:hover, #sone .post .unlike button:hover { +#sone .post .distrust button { + color: rgb(255, 0, 0); +} + +#sone .post .untrust button { + color: rgb(64, 64, 64); +} + +#sone .post .delete button:hover, #sone .post .like button:hover, #sone .post .unlike button:hover, #sone .post .trust button:hover, #sone .post .distrust button:hover, #sone .post .untrust button:hover { border: 0px; background: none; padding: 0px; @@ -257,10 +276,6 @@ textarea { cursor: pointer; } -#sone .post .delete:before, #sone .post .likes:before, #sone .post .like:before, #sone .post .unlike:before { - content: ' ‧ '; -} - #sone .post .likes span { font: inherit; color: green; @@ -325,10 +340,6 @@ textarea { color: rgb(255, 172, 0); } -#sone .post .show-reply-form:before { - content: ' ‧ '; -} - #sone .post .create-reply { clear: both; background-color: #f0f0ff; diff --git a/src/main/resources/static/javascript/sone.js b/src/main/resources/static/javascript/sone.js index 2d6c8ec..80d039c 100644 --- a/src/main/resources/static/javascript/sone.js +++ b/src/main/resources/static/javascript/sone.js @@ -68,6 +68,7 @@ function addCommentLink(postId, element, insertAfterThisElement) { return; } commentElement = (function(postId) { + separator = $(" · ").addClass("separator"); var commentElement = $("
Comment
").addClass("show-reply-form").click(function() { markPostAsKnown(getPostElement(this)); replyElement = $("#sone .post#" + postId + " .create-reply"); @@ -87,6 +88,7 @@ function addCommentLink(postId, element, insertAfterThisElement) { return commentElement; })(postId); $(insertAfterThisElement).after(commentElement.clone(true)); + $(insertAfterThisElement).after(separator); } var translations = {}; @@ -301,6 +303,17 @@ function getPostTime(element) { return getPostElement(element).find(".post-time").text(); } +/** + * Returns the author of the post the given element belongs to. + * + * @param element + * The element whose post to get the author for + * @returns The ID of the authoring Sone + */ +function getPostAuthor(element) { + return getPostElement(element).find(".post-author").text(); +} + function getReplyElement(element) { return $(element).closest(".reply"); } @@ -313,6 +326,17 @@ function getReplyTime(element) { return getReplyElement(element).find(".reply-time").text(); } +/** + * Returns the author of the reply the given element belongs to. + * + * @param element + * The element whose reply to get the author for + * @returns The ID of the authoring Sone + */ +function getReplyAuthor(element) { + return getReplyElement(element).find(".reply-author").text(); +} + function likePost(postId) { $.getJSON("like.ajax", { "type": "post", "post" : postId, "formPassword": getFormPassword() }, function(data, textStatus) { if ((data == null) || !data.success) { @@ -377,6 +401,74 @@ function unlikeReply(replyId) { }); } +/** + * Trusts the Sone with the given ID. + * + * @param soneId + * The ID of the Sone to trust + */ +function trustSone(soneId) { + $.getJSON("trustSone.ajax", { "formPassword" : getFormPassword(), "sone" : soneId }, function(data, textStatus) { + if ((data != null) && data.success) { + updateTrustControls(soneId, data.trustValue); + } + }); +} + +/** + * Distrusts the Sone with the given ID, i.e. assigns a negative trust value. + * + * @param soneId + * The ID of the Sone to distrust + */ +function distrustSone(soneId) { + $.getJSON("distrustSone.ajax", { "formPassword" : getFormPassword(), "sone" : soneId }, function(data, textStatus) { + if ((data != null) && data.success) { + updateTrustControls(soneId, data.trustValue); + } + }); +} + +/** + * Untrusts the Sone with the given ID, i.e. removes any trust assignment. + * + * @param soneId + * The ID of the Sone to untrust + */ +function untrustSone(soneId) { + $.getJSON("untrustSone.ajax", { "formPassword" : getFormPassword(), "sone" : soneId }, function(data, textStatus) { + if ((data != null) && data.success) { + updateTrustControls(soneId, data.trustValue); + } + }); +} + +/** + * Updates the trust controls for all posts and replies of the given Sone, + * according to the given trust value. + * + * @param soneId + * The ID of the Sone to update all trust controls for + * @param trustValue + * The trust value for the Sone + */ +function updateTrustControls(soneId, trustValue) { + $("#sone .post").each(function() { + if (getPostAuthor(this) == soneId) { + getPostElement(this).find(".post-trust").toggleClass("hidden", trustValue != null); + getPostElement(this).find(".post-distrust").toggleClass("hidden", (trustValue != null) && (trustValue < 0)); + getPostElement(this).find(".post-untrust").toggleClass("hidden", trustValue == null); + } + }); + $("#sone .reply").each(function() { + if (getReplyAuthor(this) == soneId) { + getReplyElement(this).find(".reply-trust").toggleClass("hidden", trustValue != null); + getReplyElement(this).find(".reply-distrust").toggleClass("hidden", (trustValue != null) && (trustValue < 0)); + getReplyElement(this).find(".reply-untrust").toggleClass("hidden", trustValue == null); + } + }); +} + function updateReplyLikes(replyId) { $.getJSON("getLikes.ajax", { "type": "reply", "reply": replyId }, function(data, textStatus) { if ((data != null) && data.success) { @@ -484,6 +576,20 @@ function ajaxifyPost(postElement) { return false; }); + /* convert trust control buttons to javascript functions. */ + $(postElement).find(".post-trust").submit(function() { + trustSone(getPostAuthor(this)); + return false; + }); + $(postElement).find(".post-distrust").submit(function() { + distrustSone(getPostAuthor(this)); + return false; + }); + $(postElement).find(".post-untrust").submit(function() { + untrustSone(getPostAuthor(this)); + return false; + }); + /* add “comment” link. */ addCommentLink(getPostId(postElement), postElement, $(postElement).find(".post-status-line .time")); @@ -537,6 +643,20 @@ function ajaxifyReply(replyElement) { })(replyElement); addCommentLink(getPostId(replyElement), replyElement, $(replyElement).find(".reply-status-line .time")); + /* convert trust control buttons to javascript functions. */ + $(replyElement).find(".reply-trust").submit(function() { + trustSone(getReplyAuthor(this)); + return false; + }); + $(replyElement).find(".reply-distrust").submit(function() { + distrustSone(getReplyAuthor(this)); + return false; + }); + $(replyElement).find(".reply-untrust").submit(function() { + untrustSone(getReplyAuthor(this)); + return false; + }); + /* mark post and all replies as known on click. */ $(replyElement).click(function() { markPostAsKnown(getPostElement(this)); diff --git a/src/main/resources/templates/dismissNotification.html b/src/main/resources/templates/dismissNotification.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/dismissNotification.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/followSone.html b/src/main/resources/templates/followSone.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/followSone.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/include/viewPost.html b/src/main/resources/templates/include/viewPost.html index cd6cc5c..a19ee73 100644 --- a/src/main/resources/templates/include/viewPost.html +++ b/src/main/resources/templates/include/viewPost.html @@ -1,6 +1,7 @@
+
Avatar Image
@@ -19,6 +20,7 @@
+ ·
↑
<%ifnull ! currentSone> <%/if> + <%if !post.sone.current> + · +
+ + + + +
+
+ + + + +
+
+ + + + +
+ <%/if> <%if post.sone.current> + ·
diff --git a/src/main/resources/templates/include/viewReply.html b/src/main/resources/templates/include/viewReply.html index f65a201..8c6884b 100644 --- a/src/main/resources/templates/include/viewReply.html +++ b/src/main/resources/templates/include/viewReply.html @@ -1,6 +1,7 @@
+
Avatar Image
@@ -11,6 +12,7 @@
<% reply.time|date format="MMM d, yyyy, HH:mm:ss">
+ ·
↑
<%ifnull ! currentSone> @@ -28,7 +30,29 @@ <%/if> + <%if !reply.sone.current> + · +
+ + + + +
+
+ + + + +
+
+ + + + +
+ <%/if> <%if reply.sone.current> + ·
diff --git a/src/main/resources/templates/like.html b/src/main/resources/templates/like.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/like.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/lockSone.html b/src/main/resources/templates/lockSone.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/lockSone.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/logout.html b/src/main/resources/templates/logout.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/logout.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/options.html b/src/main/resources/templates/options.html index f0baa50..5c47764 100644 --- a/src/main/resources/templates/options.html +++ b/src/main/resources/templates/options.html @@ -20,6 +20,17 @@

<%= Page.Options.Option.InsertionDelay.Description|l10n|html>

+

<%= Page.Options.Section.TrustOptions.Title|l10n|html>

+ +

<%= Page.Options.Option.PositiveTrust.Description|l10n|html>

+

+ +

<%= Page.Options.Option.NegativeTrust.Description|l10n|html>

+

+ +

<%= Page.Options.Option.TrustComment.Description|l10n|html>

+

+

<%= Page.Options.Section.RescueOptions.Title|l10n|html>

<%= Page.Options.Option.SoneRescueMode.Description|l10n|html>

diff --git a/src/main/resources/templates/unfollowSone.html b/src/main/resources/templates/unfollowSone.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/unfollowSone.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/unlike.html b/src/main/resources/templates/unlike.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/unlike.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html> diff --git a/src/main/resources/templates/unlockSone.html b/src/main/resources/templates/unlockSone.html deleted file mode 100644 index 196af72..0000000 --- a/src/main/resources/templates/unlockSone.html +++ /dev/null @@ -1,3 +0,0 @@ -<%include include/head.html> - -<%include include/tail.html>