Merge commit '0.3.1-RC3' into message-recipient
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Nov 2010 22:02:14 +0000 (23:02 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Nov 2010 22:02:14 +0000 (23:02 +0100)
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
src/main/java/net/pterodactylus/sone/data/Post.java
src/main/java/net/pterodactylus/sone/web/CreatePostPage.java
src/main/java/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.java
src/main/resources/i18n/sone.en.properties
src/main/resources/static/css/sone.css
src/main/resources/static/javascript/sone.js
src/main/resources/templates/include/viewPost.html
src/main/resources/templates/insert/sone.xml
src/main/resources/templates/viewSone.html

index 54908d8..bdea989 100644 (file)
@@ -1016,13 +1016,18 @@ public class Core implements IdentityListener {
                        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. */
@@ -1140,6 +1145,9 @@ public class Core implements IdentityListener {
                        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());
                        }
@@ -1208,11 +1216,48 @@ public class Core implements IdentityListener {
         * @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);
                }
index 0cedc15..fa0063e 100644 (file)
@@ -295,6 +295,7 @@ public class SoneDownloader extends AbstractService {
                } 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)) {
@@ -303,7 +304,11 @@ public class SoneDownloader extends AbstractService {
                                        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 });
index 654b827..21ba42d 100644 (file)
@@ -44,6 +44,9 @@ public class Post {
        /** 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;
 
@@ -140,6 +143,27 @@ public class Post {
        }
 
        /**
+        * 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)
index 10a8c7a..a8e2128 100644 (file)
@@ -55,8 +55,10 @@ public class CreatePostPage extends SoneTemplatePage {
                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);
index 0d553cc..ce2462c 100644 (file)
@@ -48,11 +48,13 @@ public class CreatePostAjaxPage extends JsonPage {
                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());
        }
 
index 0db2276..32ff6c6 100644 (file)
@@ -89,6 +89,7 @@ Page.ViewSone.Title=View Sone - Sone
 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.
 
@@ -149,6 +150,7 @@ View.Sone.Status.Idle=This Sone is idle, i.e. not being inserted or downloaded.
 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
@@ -156,6 +158,7 @@ View.Post.LikeLink=Like
 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)
index 608a4e8..2861575 100644 (file)
@@ -177,7 +177,7 @@ textarea {
        min-height: 48px;
 }
 
-#sone .post .author {
+#sone .post .author, #sone .post .recipient {
        display: inline;
        font-weight: bold;
 }
index ba78d2c..75facb3 100644 (file)
@@ -753,6 +753,21 @@ $(document).ready(function() {
                });
        });
 
+       /* 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) {
index e351fd0..ffc7608 100644 (file)
@@ -7,6 +7,14 @@
        <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|html></div>
                </div>
                <div class="post-status-line status-line">
index d6dd643..4e8cbae 100644 (file)
@@ -21,6 +21,7 @@
                <%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>
index 534c5ff..4d96fab 100644 (file)
@@ -1,5 +1,7 @@
 <%include include/head.html>
 
+       <div id="sone-id" class="hidden"><% sone.id|html></div>
+
        <%ifnull sone>
 
                <h1><%= Page.ViewSone.Page.TitleWithoutSone|l10n|html></h1>
                        <%include include/viewSone.html>
                <%/if>
 
+               <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>
+
                <h1><%= Page.ViewSone.PostList.Title|l10n|insert needle="{sone}" key=sone.niceName|html></h1>
 
                <div id="posts">