if (postId == null) {
break;
}
+ String postRecipientId = configuration.getStringValue(postPrefix + "/Recipient").getValue(null);
long postTime = configuration.getLongValue(postPrefix + "/Time").getValue((long) 0);
String postText = configuration.getStringValue(postPrefix + "/Text").getValue(null);
if ((postTime == 0) || (postText == null)) {
logger.log(Level.WARNING, "Invalid post found, aborting load!");
return;
}
- posts.add(getPost(postId).setSone(sone).setTime(postTime).setText(postText));
+ Post post = getPost(postId).setSone(sone).setTime(postTime).setText(postText);
+ if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
+ post.setRecipient(getSone(postRecipientId));
+ }
+ posts.add(post);
}
/* load replies. */
for (Post post : sone.getPosts()) {
String postPrefix = sonePrefix + "/Posts/" + postCounter++;
configuration.getStringValue(postPrefix + "/ID").setValue(post.getId());
+ if (post.getRecipient() != null) {
+ configuration.getStringValue(postPrefix + "/Recipient").setValue(post.getRecipient().getId());
+ }
configuration.getLongValue(postPrefix + "/Time").setValue(post.getTime());
configuration.getStringValue(postPrefix + "/Text").setValue(post.getText());
}
* @return The created post
*/
public Post createPost(Sone sone, long time, String text) {
+ return createPost(sone, null, time, text);
+ }
+
+ /**
+ * Creates a new post.
+ *
+ * @param sone
+ * The Sone that creates the post
+ * @param recipient
+ * The recipient Sone, or {@code null} if this post does not have
+ * a recipient
+ * @param text
+ * The text of the post
+ * @return The created post
+ */
+ public Post createPost(Sone sone, Sone recipient, String text) {
+ return createPost(sone, recipient, System.currentTimeMillis(), text);
+ }
+
+ /**
+ * Creates a new post.
+ *
+ * @param sone
+ * The Sone that creates the post
+ * @param recipient
+ * The recipient Sone, or {@code null} if this post does not have
+ * a recipient
+ * @param time
+ * The time of the post
+ * @param text
+ * The text of the post
+ * @return The created post
+ */
+ public Post createPost(Sone sone, Sone recipient, long time, String text) {
if (!isLocalSone(sone)) {
logger.log(Level.FINE, "Tried to create post for non-local Sone: %s", sone);
return null;
}
Post post = new Post(sone, time, text);
+ if (recipient != null) {
+ post.setRecipient(recipient);
+ }
synchronized (posts) {
posts.put(post.getId(), post);
}
} else {
for (SimpleXML postXml : postsXml.getNodes("post")) {
String postId = postXml.getValue("id", null);
+ String postRecipientId = postXml.getValue("recipient", null);
String postTime = postXml.getValue("time", null);
String postText = postXml.getValue("text", null);
if ((postId == null) || (postTime == null) || (postText == null)) {
return null;
}
try {
- posts.add(core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText));
+ Post post = core.getPost(postId).setSone(sone).setTime(Long.parseLong(postTime)).setText(postText);
+ if ((postRecipientId != null) && (postRecipientId.length() == 43)) {
+ post.setRecipient(core.getSone(postRecipientId));
+ }
+ posts.add(post);
} catch (NumberFormatException nfe1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, "Downloaded post for Sone %s with invalid time: %s", new Object[] { sone, postTime });
/** The Sone this post belongs to. */
private volatile Sone sone;
+ /** The Sone of the recipient. */
+ private volatile Sone recipient;
+
/** The time of the post (in milliseconds since Jan 1, 1970 UTC). */
private volatile long time;
}
/**
+ * Returns the recipient of this post, if any.
+ *
+ * @return The recipient of this post, or {@code null}
+ */
+ public Sone getRecipient() {
+ return recipient;
+ }
+
+ /**
+ * Sets the recipient of this post.
+ *
+ * @param recipient
+ * The recipient of this post, or {@code null}
+ * @return This post (for method chaining)
+ */
+ public Post setRecipient(Sone recipient) {
+ this.recipient = recipient;
+ return this;
+ }
+
+ /**
* Returns the time of the post.
*
* @return The time of the post (in milliseconds since Jan 1, 1970 UTC)
if (request.getMethod() == Method.POST) {
String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim();
if (text.length() != 0) {
+ String recipientId = request.getHttpRequest().getPartAsStringFailsafe("recipient", 43);
+ Sone recipient = webInterface.getCore().getSone(recipientId, false);
Sone currentSone = getCurrentSone(request.getToadletContext());
- webInterface.getCore().createPost(currentSone, System.currentTimeMillis(), text);
+ webInterface.getCore().createPost(currentSone, recipient, System.currentTimeMillis(), text);
throw new RedirectException(returnPage);
}
template.set("errorTextEmpty", true);
if (sone == null) {
return createErrorJsonObject("auth-required");
}
+ String recipientId = request.getHttpRequest().getParam("recipient");
+ Sone recipient = webInterface.getCore().getSone(recipientId, false);
String text = request.getHttpRequest().getParam("text");
if ((text == null) || (text.trim().length() == 0)) {
return createErrorJsonObject("text-required");
}
- Post newPost = webInterface.getCore().createPost(sone, text);
+ Post newPost = webInterface.getCore().createPost(sone, recipient, text);
return createSuccessJsonObject().put("postId", newPost.getId());
}
Page.ViewSone.Page.TitleWithoutSone=View unknown Sone
Page.ViewSone.NoSone.Description=There is currently no known Sone with the ID {sone}. If you were looking for a specific Sone, make sure that it is visible in your web of trust!
Page.ViewSone.UnknownSone.Description=This Sone has not yet been retrieved. Please check back in a short time.
+Page.ViewSone.WriteAMessage=You can write a message to this Sone here. Please note that everybody will be able to read this message!
Page.ViewSone.PostList.Title=Posts by {sone}
Page.ViewSone.PostList.Text.NoPostYet=This Sone has not yet posted anything.
View.Sone.Status.Downloading=This Sone is currently being downloaded.
View.Sone.Status.Inserting=This Sone is currently being inserted.
+View.Post.UnknownAuthor=(unknown)
View.Post.DeleteLink=Delete
View.Post.SendReply=Post Reply!
View.Post.Reply.DeleteLink=Delete
View.Post.UnlikeLink=Unlike
WebInterface.DefaultText.StatusUpdate=What’s on your mind?
+WebInterface.DefaultText.Message=Write a Message…
WebInterface.DefaultText.Reply=Write a Reply…
WebInterface.DefaultText.FirstName=First name
WebInterface.DefaultText.MiddleName=Middle name(s)
min-height: 48px;
}
-#sone .post .author {
+#sone .post .author, #sone .post .recipient {
display: inline;
font-weight: bold;
}
});
});
+ /* ajaxify input field on “view Sone” page. */
+ getTranslation("WebInterface.DefaultText.Message", function(defaultText) {
+ registerInputTextareaSwap("#sone #post-message input[name=text]", defaultText, "text", false, false);
+ $("#sone #post-message").submit(function() {
+ text = $(this).find(":input:enabled").val();
+ $.getJSON("ajax/createPost.ajax", { "formPassword": getFormPassword(), "recipient": $("#sone #sone-id").text(), "text": text }, function(data, textStatus) {
+ if ((data != null) && data.success) {
+ loadNewPost(data.postId);
+ }
+ });
+ $(this).find(":input:enabled").val("").blur();
+ return false;
+ });
+ });
+
/* Ajaxifies all posts. */
/* calling getTranslation here will cache the necessary values. */
getTranslation("WebInterface.Confirmation.DeletePostButton", function(text) {
<div class="inner-part">
<div>
<div class="author profile-link"><a href="viewSone.html?sone=<% post.sone.id|html>"><% post.sone.niceName|html></a></div>
+ <%ifnull !post.recipient>
+ <span class="recipient-to">→</span>
+ <%ifnull post.recipient.identity>
+ <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><% View.Post.UnknownAuthor|l10n|html></a></div>
+ <%else>
+ <div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><% post.recipient.niceName|html></a></div>
+ <%/if>
+ <%/if>
<div class="text"><% post.text></div>
</div>
<div class="post-status-line status-line">
<%foreach currentSone.posts post>
<post>
<id><% post.id|xml></id>
+ <recipient><%ifnull !post.recipient><% post.recipient.id|xml><%/if></recipient>
<time><% post.time></time>
<text><% post.text|xml></text>
</post>
<%if ! sone.current>
<%include include/viewSone.html>
+
+ <p><%= Page.ViewSone.WriteAMessage|l10n|html></p>
+
+ <form action="createPost.html" id="post-message" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="recipient" value="<% sone.id|html>" />
+ <input type="text" name="text" value="" />
+ <button type="submit"><%= Page.CreatePost.Button.Post|l10n|html></button>
+ </form>
<%/if>
+
<h1><%= Page.ViewSone.PostList.Title|l10n|insert needle="{sone}" key=sone.niceName|html></h1>
<div id="posts">