<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>utils</artifactId>
- <version>0.12.2</version>
+ <version>0.12.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.service.AbstractService;
+import net.pterodactylus.util.thread.NamedThreadFactory;
import net.pterodactylus.util.thread.Ticker;
import net.pterodactylus.util.validation.EqualityValidator;
import net.pterodactylus.util.validation.IntegerRangeValidator;
private final ImageInserter imageInserter;
/** Sone downloader thread-pool. */
- private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10);
+ private final ExecutorService soneDownloaders = Executors.newFixedThreadPool(10, new NamedThreadFactory("Sone Downloader %2$d"));
/** The update checker. */
private final UpdateChecker updateChecker;
if (!storedPosts.contains(post)) {
if (post.getTime() < getSoneFollowingTime(sone)) {
knownPosts.add(post.getId());
+ post.setKnown(true);
} else if (!knownPosts.contains(post.getId())) {
- sone.setKnown(false);
coreListenerManager.fireNewPostFound(post);
}
}
if (!storedReplies.contains(reply)) {
if (reply.getTime() < getSoneFollowingTime(sone)) {
knownReplies.add(reply.getId());
+ reply.setKnown(true);
} else if (!knownReplies.contains(reply.getId())) {
- reply.setKnown(false);
coreListenerManager.fireNewReplyFound(reply);
}
}
* @return The created post
*/
public Post createPost(Sone sone, Sone recipient, long time, String text) {
+ Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.length(), 0).check();
if (!isLocalSone(sone)) {
logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
return null;
* @return The created reply
*/
public PostReply createReply(Sone sone, Post post, long time, String text) {
+ Validation.begin().isNotNull("Text", text).check().isGreater("Text Length", text.trim().length(), 0).check();
if (!isLocalSone(sone)) {
logger.log(Level.FINE, String.format("Tried to create reply for non-local Sone: %s", sone));
return null;
*/
@Override
public void identityUpdated(OwnIdentity ownIdentity, final Identity identity) {
- new Thread(new Runnable() {
+ soneDownloaders.execute(new Runnable() {
@Override
@SuppressWarnings("synthetic-access")
soneDownloader.addSone(sone);
soneDownloader.fetchSone(sone);
}
- }).start();
+ });
}
/**
import net.pterodactylus.sone.freenet.fcp.Command.AccessType;
import net.pterodactylus.sone.freenet.fcp.Command.ErrorResponse;
import net.pterodactylus.sone.freenet.fcp.Command.Response;
-import net.pterodactylus.sone.freenet.fcp.FcpException;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.validation.Validation;
import freenet.pluginmanager.FredPluginFCP;
try {
Response response = command.execute(parameters, data, AccessType.values()[accessType]);
sendReply(pluginReplySender, identifier, response);
- } catch (FcpException fe1) {
+ } catch (Exception e1) {
logger.log(Level.WARNING, "Could not process FCP command “%s”.", command);
- sendReply(pluginReplySender, identifier, new ErrorResponse("Error executing command: " + fe1.getMessage()));
+ sendReply(pluginReplySender, identifier, new ErrorResponse("Error executing command: " + e1.getMessage()));
}
} catch (PluginNotFoundException pnfe1) {
logger.log(Level.WARNING, "Could not find destination plugin: " + pluginReplySender);
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
* The part to render
*/
private void render(Writer writer, LinkPart linkPart) {
- renderLink(writer, "/?_CHECKED_HTTP_=" + linkPart.getLink(), linkPart.getText(), linkPart.getTitle(), "internet");
+ try {
+ renderLink(writer, "/external-link/?_CHECKED_HTTP_=" + URLEncoder.encode(linkPart.getLink(), "UTF-8"), linkPart.getText(), linkPart.getTitle(), "internet");
+ } catch (UnsupportedEncodingException uee1) {
+ /* not possible for UTF-8. */
+ throw new RuntimeException("The JVM does not support UTF-8 encoding!", uee1);
+ }
}
/**
private enum LinkType {
/** Link is a KSK. */
- KSK,
+ KSK("KSK@"),
/** Link is a CHK. */
- CHK,
+ CHK("CHK@"),
/** Link is an SSK. */
- SSK,
+ SSK("SSK@"),
/** Link is a USK. */
- USK,
+ USK("USK@"),
/** Link is HTTP. */
- HTTP,
+ HTTP("http://"),
/** Link is HTTPS. */
- HTTPS,
+ HTTPS("https://"),
/** Link is a Sone. */
- SONE,
+ SONE("sone://"),
/** Link is a post. */
- POST,
+ POST("post://");
+
+ /** The scheme identifying this link type. */
+ private final String scheme;
+
+ /**
+ * Creates a new link type identified by the given scheme.
+ *
+ * @param scheme
+ * The scheme of the link type
+ */
+ private LinkType(String scheme) {
+ this.scheme = scheme;
+ }
+
+ /**
+ * Returns the scheme of this link type.
+ *
+ * @return The scheme of this link type
+ */
+ public String getScheme() {
+ return scheme;
+ }
}
}
lineComplete = false;
+ Matcher matcher = whitespacePattern.matcher(line);
+ int nextSpace = matcher.find(0) ? matcher.start() : line.length();
+ String link = line.substring(0, nextSpace);
+ String name = link;
+ logger.log(Level.FINER, String.format("Found link: %s", link));
+ logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
+
+ /* if there is no text after the scheme, it’s not a link! */
+ if (link.equals(linkType.getScheme())) {
+ parts.add(new PlainTextPart(linkType.getScheme()));
+ line = line.substring(linkType.getScheme().length());
+ continue;
+ }
+
if (linkType == LinkType.SONE) {
if (line.length() >= (7 + 43)) {
String soneId = line.substring(7, 50);
}
continue;
}
- Matcher matcher = whitespacePattern.matcher(line);
- int nextSpace = matcher.find(0) ? matcher.start() : line.length();
- String link = line.substring(0, nextSpace);
- String name = link;
- logger.log(Level.FINER, String.format("Found link: %s", link));
- logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
FreenetURI uri;
birthDay = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-day", 256).trim());
birthMonth = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-month", 256).trim());
birthYear = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("birth-year", 256).trim());
- avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatar-id", 36);
+ avatarId = request.getHttpRequest().getPartAsStringFailsafe("avatarId", 36);
profile.setFirstName(firstName.length() > 0 ? firstName : null);
profile.setMiddleName(middleName.length() > 0 ? middleName : null);
profile.setLastName(lastName.length() > 0 ? lastName : null);
templateContext.set("birthDay", birthDay);
templateContext.set("birthMonth", birthMonth);
templateContext.set("birthYear", birthYear);
- templateContext.set("avatar-id", avatarId);
+ templateContext.set("avatarId", avatarId);
templateContext.set("fields", fields);
}
package net.pterodactylus.sone.web.ajax;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
import java.net.URI;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetPage;
import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.json.JsonUtils;
import net.pterodactylus.util.web.Page;
return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required")));
}
}
- JsonObject jsonObject = createJsonObject(request);
- return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(JsonUtils.format(jsonObject));
+ try {
+ JsonObject jsonObject = createJsonObject(request);
+ return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(JsonUtils.format(jsonObject));
+ } catch (Exception e1) {
+ return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1));
+ }
}
/**
return false;
}
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Returns a byte array containing the stack trace of the given throwable.
+ *
+ * @param t
+ * The throwable whose stack trace to dump into an array
+ * @return The array with the stack trace, or an empty array if the stack
+ * trace could not be dumped
+ */
+ private static byte[] dumpStackTrace(Throwable t) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ OutputStreamWriter writer = null;
+ PrintWriter printWriter = null;
+ try {
+ writer = new OutputStreamWriter(byteArrayOutputStream, "uTF-8");
+ printWriter = new PrintWriter(writer);
+ t.printStackTrace(printWriter);
+ byteArrayOutputStream.flush();
+ return byteArrayOutputStream.toByteArray();
+ } catch (IOException ioe1) {
+ /* quite not possible. */
+ return new byte[0];
+ } finally {
+ Closer.close(printWriter);
+ Closer.close(writer);
+ Closer.close(byteArrayOutputStream);
+ }
+ }
+
}
View.Time.AFewSecondsAgo=au cours des dernières secondes passées
View.Time.HalfAMinuteAgo=au cours des 30 dernières secondes
View.Time.AMinuteAgo=au cours de la dernière minute
-View.Time.XMinutesAgo=${min} il y a quelques minutes
+View.Time.XMinutesAgo=il y a environs {min} minutes
View.Time.HalfAnHourAgo=au cours de la dernière demi heure
View.Time.AnHourAgo=il y a environ une heure
-View.Time.XHoursAgo=${heure} au cours des dernières heures
+View.Time.XHoursAgo=Il y a environ ${hour} heures
View.Time.ADayAgo=il y a environ un jour
-View.Time.XDaysAgo=${jour} il y a quelques jours
+View.Time.XDaysAgo=il y a plus ou moins ${day} jours
View.Time.AWeekAgo=il y a environ une semaine
-View.Time.XWeeksAgo=${semaine} au cours des dernières semaines
+View.Time.XWeeksAgo=au cours des dernières ${week}semaines
View.Time.AMonthAgo=au cours du dernier mois
-View.Time.XMonthsAgo=${mois} au cours des derniers mois
+View.Time.XMonthsAgo=au cours des derniers ${month} mois
View.Time.AYearAgo=au cours de la dernière année
-View.Time.XYearsAgo=${année} au cours des dernières années
+View.Time.XYearsAgo=au cours des dernières ${year} années
WebInterface.DefaultText.StatusUpdate=Exprimez-vous
WebInterface.DefaultText.Message=Écrire un message...
<ul id="avatar-selection">
<li id="no-avatar">
- <input type="radio" name="avatar-id" value="none"<%ifnull avatar-id> checked="checked"<%/if>/>
+ <input type="radio" name="avatarId" value="none"<%ifnull avatarId> checked="checked"<%/if>/>
<%= Page.EditProfile.Avatar.Delete|l10n|html>
</li>
<%foreach currentSone.allImages image>
<li>
- <input type="radio" name="avatar-id" value="<%image.id|html>"<%if avatar-id|match key=image.id> checked="checked"<%/if>/>
+ <input type="radio" name="avatarId" value="<%image.id|html>"<%if avatarId|match value=image.id> checked="checked"<%/if>/>
<div class="post-avatar"><% image|image-link max-width==48 max-height==48 mode==enlarge title=image.title></div>
</li>
<%/foreach>
import java.io.IOException;
import java.io.StringReader;
+import java.util.Arrays;
import junit.framework.TestCase;
import net.pterodactylus.sone.core.SoneProvider;
assertEquals("Part Text", "Some text.\n\nLink to [Sone|DAxKQzS48mtaQc7sUVHIgx3fnWZPQBz0EueBreUVWrU] and stuff.", convertText(parts, PlainTextPart.class, SonePart.class));
}
+ /**
+ * Test for a bug discovered in Sone 0.8.4 where a plain “http://” would be
+ * parsed into a link.
+ *
+ * @throws IOException
+ * if an I/O error occurs
+ */
+ @SuppressWarnings({ "synthetic-access", "static-method" })
+ public void testEmpyHttpLinks() throws IOException {
+ SoneTextParser soneTextParser = new SoneTextParser(new TestSoneProvider(), null);
+ Iterable<Part> parts;
+
+ /* check empty http links. */
+ parts = soneTextParser.parse(null, new StringReader("Some text. Empty link: http:// – nice!"));
+ assertNotNull("Parts", parts);
+ assertEquals("Part Text", "Some text. Empty link: http:// – nice!", convertText(parts, PlainTextPart.class));
+ }
+
//
// PRIVATE METHODS
//
}
}
if (!classValid) {
- assertEquals("Part’s Class", null, part.getClass());
+ fail("Part’s Class (" + part.getClass() + ") is not one of " + Arrays.toString(validClasses));
}
if (part instanceof PlainTextPart) {
text.append(((PlainTextPart) part).getText());