<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>static/images/warn_icon.gif</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -85,10 +85,8 @@ class RadarViewByIdAction(Handler):
     if (not radar):
       self.respondWithText('Invalid Radar id')
       return
-    
-    comments = Comment.gql(&quot;WHERE radar = :1&quot;, radar)
       
-    self.respondWithTemplate('radar-view.html', {&quot;radar&quot;:radar, &quot;comments&quot;: comments})
+    self.respondWithTemplate('radar-view.html', {&quot;radar&quot;:radar, &quot;comments&quot;: radar.comments()})
 
 class RadarViewByNumberAction(Handler):
   def get(self):    
@@ -102,9 +100,7 @@ class RadarViewByNumberAction(Handler):
       self.respondWithText('Invalid Radar id')
       return
     
-    comments = Comment.gql(&quot;WHERE radar = :1 AND is_reply_to = :2&quot;, radar, None)
-    
-    self.respondWithTemplate('radar-view.html', {&quot;radar&quot;:radar, &quot;comments&quot;: comments})
+    self.respondWithTemplate('radar-view.html', {&quot;radar&quot;:radar, &quot;comments&quot;: radar.comments()})
 
 class RadarEditAction(Handler):
   def get(self):    
@@ -258,7 +254,7 @@ class APISecretAction(Handler):
     self.respondWithDictionaryAsJSON({&quot;name&quot;:name, &quot;value&quot;:value})
 
 
-class CommentsAJAXForm(Handler):
+class CommentsAJAXFormAction(Handler):
   def _check(self):
     user = users.GetCurrentUser()
     if (not user):
@@ -289,7 +285,7 @@ class CommentsAJAXForm(Handler):
     args = {&quot;radar&quot;: radar}
     
     if(replyTo):
-      args[&quot;is_reply_to&quot;] = post
+      args[&quot;is_reply_to&quot;] = replyTo
     
     self.respondWithText(Comment(**args).form())
     
@@ -316,7 +312,31 @@ class CommentsAJAXForm(Handler):
     
     self.respondWithText(comment.draw())
     
-
+class CommentsAJAXRemoveAction(Handler):
+  def post(self):
+    user = users.GetCurrentUser()
+    if (not user):
+      self.error(401)
+      self.respondWithText(&quot;You must login to remove a comment&quot;)
+      return
+    
+    commentKey = self.request.get(&quot;key&quot;)
+    comment = Comment.get(commentKey)
+    if(not comment):
+      self.error(400)
+      self.respondWithText(&quot;Tried to remove a post that doesn't exist? Couldn't find post to remove.&quot;)
+      return
+    
+    if(not comment.editable_by_current_user()):
+      self.error(401)
+      self.respondWithText(&quot;You must be the comment's owner, or an admin, to remove this comment.&quot;)
+      return
+    
+    if(comment.deleteOrBlank() == &quot;blanked&quot;):
+      self.respondWithText(comment.html_body())
+    else:
+      self.respondWithText(&quot;REMOVED&quot;)
+    
 
 def main():
   application = webapp.WSGIApplication([
@@ -332,7 +352,8 @@ def main():
     ('/api/test', APITestAction),
     ('/api/radars', APIRadarsAction),
     ('/api/radars/add', APIAddRadarAction),
-    ('/comment', CommentsAJAXForm),
+    ('/comment', CommentsAJAXFormAction),
+    ('/comment/remove', CommentsAJAXRemoveAction),
     # intentially disabled 
     # ('/api/secret', APISecretAction),
     ('.*', NotFoundAction)</diff>
      <filename>main.py</filename>
    </modified>
    <modified>
      <diff>@@ -32,6 +32,9 @@ class Radar(db.Model):
   def put(self):
     self.modified = datetime.datetime.now() 
     db.Model.put(self)
+    
+  def comments(self):
+    return Comment.gql(&quot;WHERE radar = :1 AND is_reply_to = :2&quot;, self, None)
 
 import markdown
 md = markdown.Markdown()
@@ -46,7 +49,7 @@ class Comment(db.Model):
   
   def __init__(self, *args, **kwargs):
     super(Comment, self).__init__(*args, **kwargs)
-    self.posted_at = datetime.datetime.now()
+    if(not self.posted_at): self.posted_at = datetime.datetime.now()
     if(not self.body): self.body = &quot;&quot;
     if(not self.subject): self.subject = &quot;&quot;
     
@@ -74,3 +77,18 @@ class Comment(db.Model):
   def html_body(self):
     return md.convert(self.body)
 
+  def editable_by_current_user(self):
+    from google.appengine.api import users
+    user = users.GetCurrentUser()
+    return user == self.user or users.is_current_user_admin()
+    
+  def deleteOrBlank(self):
+    if self.replies().count() &gt; 0:
+      self.subject = &quot;(Removed)&quot;
+      self.body = &quot;*This comment has been removed by its author or a moderator.*&quot;
+      self.put()
+      return &quot;blanked&quot;
+    else:
+      self.delete()
+      return &quot;deleted&quot;
+  
\ No newline at end of file</diff>
      <filename>models.py</filename>
    </modified>
    <modified>
      <diff>@@ -256,7 +256,7 @@ div.indent {
 	color: #66b;
 }
 
-.comment input,
+.comment h3 input,
 .comment textarea {
 	width:  100%;
 }</diff>
      <filename>static/css/screen.css</filename>
    </modified>
    <modified>
      <diff>@@ -52,4 +52,54 @@ function submitComment(form) {
     }
   })
   
+}
+
+function replyForm(somethingInsideTheComment) {
+  var comment = jQuery(somethingInsideTheComment).parents(&quot;.comment&quot;)
+  var parent_key = comment.children(&quot;.keyref&quot;)[0].name
+
+  jQuery.ajax({
+    url: &quot;/comment&quot;,
+    type: &quot;get&quot;,
+    data: {
+      radar: jQuery(&quot;#radar&quot;).text(),
+      is_reply_to: parent_key
+    },
+    success: function(commentForm) {
+      comment.parent(&quot;.commentWithReplies&quot;).children(&quot;.indent&quot;).append(commentForm).children(&quot;:last&quot;).hide().slideDown()
+    },
+    error: function(xhr, textStatus, errorThrown) {
+      showError(xhr.responseText)
+    }
+  }) 
+}
+
+function removeComment(somethingInsideTheComment) {
+  if(!confirm(&quot;Are you sure you want to remove this comment? You can't undo this.&quot;))
+    return
+  
+  var comment = jQuery(somethingInsideTheComment).parents(&quot;.comment&quot;)
+  var remove_key = comment.children(&quot;.keyref&quot;)[0].name
+  jQuery.ajax({
+    url: &quot;/comment/remove&quot;,
+    type: &quot;post&quot;,
+    data: {
+      radar: jQuery(&quot;#radar&quot;).text(),
+      key: remove_key
+    },
+    success: function(removalText) {
+      if(removalText.indexOf(&quot;REMOVED&quot;)==0) {
+        comment.parent(&quot;.commentWithReplies&quot;).slideUp(function() {
+          comment.parent(&quot;.commentWithReplies&quot;).remove()
+        })
+      }else {
+        comment.children(&quot;h3&quot;).text(&quot;(Removed)&quot;)
+        comment.children(&quot;.commentbody&quot;).html(removalText)
+      }
+    },
+    error: function(xhr, textStatus, errorThrown) {
+      showError(xhr.responseText)
+    }
+  }) 
+  
 }
\ No newline at end of file</diff>
      <filename>static/js/comments.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,7 +10,13 @@
       &lt;textarea name=&quot;body&quot; rows=&quot;10&quot;&gt;{{ comment.body }}&lt;/textarea&gt;
     &lt;/div&gt;
     &lt;div class=&quot;meta&quot;&gt;
-      &lt;input type=&quot;submit&quot; value=&quot;Post message&quot;/&gt;
+      {% if comment.is_saved %}
+        &lt;input type=&quot;button&quot; value=&quot;Cancel&quot; /&gt;
+        &lt;input type=&quot;submit&quot; value=&quot;Edit&quot; /&gt;
+      {% else %}
+        &lt;input type=&quot;button&quot; value=&quot;Cancel&quot; /&gt;
+        &lt;input type=&quot;submit&quot; value=&quot;Post message&quot; /&gt;
+      {% endif %}
     &lt;/div&gt;
   &lt;/div&gt;
 &lt;/form&gt;
\ No newline at end of file</diff>
      <filename>templates/comment-form.html</filename>
    </modified>
    <modified>
      <diff>@@ -1,16 +1,24 @@
-&lt;div class=&quot;comment&quot;&gt;
-  &lt;a name=&quot;{{comment.key}}&quot;&gt;&lt;/a&gt;
-  &lt;h3&gt;{{ comment.subject }}&lt;/h3&gt;
-  &lt;div class=&quot;commentbody&quot;&gt;
-    {{ comment.html_body }}
+&lt;div class=&quot;commentWithReplies&quot;&gt;
+  &lt;div class=&quot;comment&quot;&gt;
+    &lt;a class=&quot;keyref&quot; name=&quot;{{comment.key}}&quot;&gt;&lt;/a&gt;
+    &lt;h3&gt;{{ comment.subject }}&lt;/h3&gt;
+    &lt;div class=&quot;commentbody&quot;&gt;
+      {{ comment.html_body }}
+    &lt;/div&gt;
+    &lt;div class=&quot;meta&quot;&gt;
+      By &lt;a href=&quot;mailto:{{comment.user.email}}&quot;&gt;{{ comment.user }}&lt;/a&gt; at
+      &lt;a href=&quot;#{{comment.key}}&quot;&gt;{{ comment.posted_at }}&lt;/a&gt;
+      (&lt;a href=&quot;#&quot; onclick=&quot;javascript:replyForm(this); return false&quot;&gt;reply...&lt;/a&gt;)
+      {% if comment.editable_by_current_user %}
+        &lt;input type=&quot;button&quot; name=&quot;edit&quot; value=&quot;Edit&quot; /&gt;
+        &lt;input type=&quot;button&quot; name=&quot;remove&quot; value=&quot;Remove&quot; onclick=&quot;javascript:removeComment(this); return false;&quot;/&gt;
+      {% endif %}
+    &lt;/div&gt;
   &lt;/div&gt;
-  &lt;div class=&quot;meta&quot;&gt;
-    By &lt;a href=&quot;mailto:{{comment.user.email}}&quot;&gt;{{ comment.user }}&lt;/a&gt; at &lt;a href=&quot;#{{comment.key}}&quot;&gt;{{ comment.posted_at }}&lt;/a&gt; (&lt;a href=&quot;#&quot;&gt;reply...&lt;/a&gt;)
-  &lt;/div&gt;
-&lt;/div&gt;
 
-&lt;div class=&quot;indent&quot;&gt;
-  {% for reply in comment.replies %}
-    {{ reply.draw }}
-  {% endfor %}
+  &lt;div class=&quot;indent&quot;&gt;
+    {% for reply in comment.replies %}
+      {{ reply.draw }}
+    {% endfor %}
+  &lt;/div&gt;
 &lt;/div&gt;
\ No newline at end of file</diff>
      <filename>templates/comment.html</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>2a7f377134d4041b7553fe47b123292b2dd616bb</id>
    </parent>
  </parents>
  <author>
    <name>Joachim Bengtsson</name>
    <email>joachimb@gmail.com</email>
  </author>
  <url>http://github.com/timburks/openradar/commit/85b74cd28dfa6e4bcf6e58c0c6268bc4b0acd6ec</url>
  <id>85b74cd28dfa6e4bcf6e58c0c6268bc4b0acd6ec</id>
  <committed-date>2008-11-21T00:51:54-08:00</committed-date>
  <authored-date>2008-11-21T00:51:54-08:00</authored-date>
  <message>Removal works fine</message>
  <tree>8ede0587653fef188614b6349ddd0edb901a71b3</tree>
  <committer>
    <name>Joachim Bengtsson</name>
    <email>joachimb@gmail.com</email>
  </committer>
</commit>
