Browse Source

Advancements in private replies functionality

Ralfp 12 years ago
parent
commit
e5892dc413

+ 1 - 1
misago/acl/permissions/privatethreads.py

@@ -71,7 +71,7 @@ def cleanup(acl, perms, forums):
                 acl.forums.acl['can_see'].append(forum)
                 acl.forums.acl['can_browse'].append(forum)
             if perm['can_start_private_threads']:
-                acl.threads.acl[forum]['can_start_threads'] = True
+                acl.threads.acl[forum]['can_start_threads'] = 2
             if perm['can_upload_attachments_in_private_threads']:
                 acl.threads.acl[forum]['can_upload_attachments'] = True
             if perm['private_thread_attachment_size']:

+ 7 - 1
misago/apps/privatethreads/forms.py

@@ -1,3 +1,5 @@
+from django import forms
+from misago.forms import Form
 from misago.apps.threadtype.posting.forms import (NewThreadForm as NewThreadBaseForm,
                                                   EditThreadForm as EditThreadBaseForm,
                                                   NewReplyForm as NewReplyBaseForm,
@@ -20,4 +22,8 @@ class NewReplyForm(NewReplyBaseForm):
 
 class EditReplyForm(EditReplyBaseForm):
     include_thread_weight = False
-    include_close_thread = False
+    include_close_thread = False
+
+
+class InviteMemberForm(Form):
+    username = forms.CharField(max_length=200)

+ 10 - 8
misago/apps/privatethreads/jumps.py

@@ -13,14 +13,6 @@ class NewReplyView(NewReplyBaseView, TypeMixin):
     pass
 
 
-class FirstModeratedView(FirstModeratedBaseView, TypeMixin):
-    pass
-
-
-class FirstReportedView(FirstReportedBaseView, TypeMixin):
-    pass
-
-
 class ShowHiddenRepliesView(ShowHiddenRepliesBaseView, TypeMixin):
     pass
 
@@ -47,3 +39,13 @@ class UpvotePostView(UpvotePostBaseView, TypeMixin):
 
 class DownvotePostView(DownvotePostBaseView, TypeMixin):
     pass
+
+
+class InviteUserView(JumpView, TypeMixin):
+    def make_jump(self):
+        print 'ZOMG INVITING USER'
+
+
+class RemoveUserView(JumpView, TypeMixin):
+    def make_jump(self):
+        print 'ZOMG REMOVING USER'

+ 2 - 2
misago/apps/privatethreads/posting.py

@@ -23,7 +23,7 @@ class NewThreadView(NewThreadBaseView, TypeMixin):
             self.request.messages.set_flash(Message(_("New thread has been posted. It will be hidden from other members until moderator reviews it.")), 'success', 'threads')
         else:
             self.request.messages.set_flash(Message(_("New thread has been posted.")), 'success', 'threads')
-        return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
+        return redirect(reverse('private_thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
 
 
 class EditThreadView(EditThreadBaseView, TypeMixin):
@@ -34,7 +34,7 @@ class EditThreadView(EditThreadBaseView, TypeMixin):
     
     def response(self):
         self.request.messages.set_flash(Message(_("Your thread has been edited.")), 'success', 'threads_%s' % self.post.pk)
-        return redirect(reverse('thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
+        return redirect(reverse('private_thread', kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % self.post.pk))
 
 
 class NewReplyView(NewReplyBaseView, TypeMixin):

+ 8 - 1
misago/apps/privatethreads/thread.py

@@ -1,7 +1,9 @@
 from django.utils.translation import ugettext as _
 from misago.apps.threadtype.thread import ThreadBaseView, ThreadModeration, PostsModeration
+from misago.forms import FormFields
 from misago.models import Forum, Thread
 from misago.apps.privatethreads.mixins import TypeMixin
+from misago.apps.privatethreads.forms import InviteMemberForm
 
 class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
     def posts_actions(self):
@@ -41,4 +43,9 @@ class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
                 actions.append(('hard', _('Hard delete this thread')))
         except KeyError:
             pass
-        return actions
+        return actions
+
+    def template_vars(self, context):
+        context['participants'] = self.thread.participants.all().prefetch_related('rank')
+        context['invite_form'] = FormFields(InviteMemberForm(request=self.request))
+        return context

+ 3 - 0
misago/apps/threadtype/base.py

@@ -46,3 +46,6 @@ class ViewBase(object):
         if pagination['total'] > 1:
             return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug, 'page': pagination['total']}) + ('#post-%s' % post.pk))
         return redirect(reverse(self.type_prefix, kwargs={'thread': self.thread.pk, 'slug': self.thread.slug}) + ('#post-%s' % post.pk))
+
+    def template_vars(self, context):
+        return context

+ 4 - 4
misago/apps/threadtype/changelog.py

@@ -53,14 +53,14 @@ class ChangelogBaseView(ViewBase):
 class ChangelogChangesBaseView(ChangelogBaseView):
     def dispatch(self, request, **kwargs):
         return request.theme.render_to_response('%ss/changelog.html' % self.type_prefix,
-                                                {
+                                                self.template_vars({
                                                  'type_prefix': self.type_prefix,
                                                  'forum': self.forum,
                                                  'parents': self.parents,
                                                  'thread': self.thread,
                                                  'post': self.post,
                                                  'edits': self.post.change_set.prefetch_related('user').order_by('-id')
-                                                 },
+                                                 }),
                                                 context_instance=RequestContext(request))
 
 
@@ -80,7 +80,7 @@ class ChangelogDiffBaseView(ChangelogBaseView):
             prev = None
         self.forum.closed = self.proxy.closed
         return request.theme.render_to_response('%ss/changelog_diff.html' % self.type_prefix,
-                                                {
+                                                self.template_vars({
                                                  'type_prefix': self.type_prefix,
                                                  'forum': self.forum,
                                                  'parents': self.parents,
@@ -92,7 +92,7 @@ class ChangelogDiffBaseView(ChangelogBaseView):
                                                  'message': request.messages.get_message('changelog'),
                                                  'l': 1,
                                                  'diff': difflib.ndiff(self.change.post_content.splitlines(), self.post.post.splitlines()),
-                                                 },
+                                                 }),
                                                 context_instance=RequestContext(request))
 
 

+ 4 - 4
misago/apps/threadtype/details.py

@@ -44,13 +44,13 @@ class DetailsBaseView(ExtraBaseView):
 
     def response(self):
         return self.request.theme.render_to_response('%ss/details.html' % self.type_prefix,
-                                                     {
+                                                     self.template_vars({
                                                       'type_prefix': self.type_prefix,
                                                       'forum': self.forum,
                                                       'parents': self.parents,
                                                       'thread': self.thread,
                                                       'post': self.post,
-                                                     },
+                                                     }),
                                                      context_instance=RequestContext(self.request))
 
 
@@ -60,7 +60,7 @@ class KarmaVotesBaseView(ExtraBaseView):
 
     def response(self):
         return self.request.theme.render_to_response('%ss/karmas.html' % self.type_prefix,
-                                                     {
+                                                     self.template_vars({
                                                       'type_prefix': self.type_prefix,
                                                       'forum': self.forum,
                                                       'parents': self.parents,
@@ -68,5 +68,5 @@ class KarmaVotesBaseView(ExtraBaseView):
                                                       'post': self.post,
                                                       'upvotes': self.post.karma_set.filter(score=1),
                                                       'downvotes': self.post.karma_set.filter(score=-1),
-                                                      },
+                                                      }),
                                                      context_instance=RequestContext(self.request))

+ 1 - 4
misago/apps/threadtype/list/views.py

@@ -86,9 +86,6 @@ class ThreadsListBaseView(ViewBase):
         else:
             self.form = self.form(request=self.request)
 
-    def template_vars(self, context):
-        return context
-
     def __call__(self, request, **kwargs):
         self.request = request
         self.kwargs = kwargs
@@ -98,7 +95,7 @@ class ThreadsListBaseView(ViewBase):
         self.message = request.messages.get_message('threads')
         try:
             self._fetch_forum()
-            self.check_permissions()
+            self._check_permissions()
             self.fetch_threads()
             self.form = None
             self.make_form()

+ 2 - 2
misago/apps/threadtype/posting/base.py

@@ -120,7 +120,7 @@ class PostingBaseView(ViewBase):
             return error404(request, unicode(e))
 
         return request.theme.render_to_response(('%ss/posting.html' % self.type_prefix),
-                                                {
+                                                self.template_vars({
                                                  'type_prefix': self.type_prefix,
                                                  'action': self.action,
                                                  'message': self.message,
@@ -131,5 +131,5 @@ class PostingBaseView(ViewBase):
                                                  'parents': self.parents,
                                                  'preview': post_preview,
                                                  'form': FormLayout(form),
-                                                 },
+                                                 }),
                                                 context_instance=RequestContext(request));

+ 3 - 1
misago/apps/threadtype/posting/newreply.py

@@ -72,9 +72,11 @@ class NewReplyBaseView(PostingBaseView):
                                         )
 
         # Update thread data and score?
+        if not moderation:
+            self.thread.new_last_post(self.post)
+
         if not merged:
             if not moderation:
-                self.thread.new_last_post(self.post)
                 self.thread.replies += 1
             else:
                 self.thread.replies_moderated += 1

+ 2 - 2
misago/apps/threadtype/thread/views.py

@@ -188,7 +188,7 @@ class ThreadBaseView(ViewBase):
         self.forum.closed = self.proxy.closed
 
         return request.theme.render_to_response('%ss/thread.html' % self.type_prefix,
-                                                {
+                                                self.template_vars({
                                                  'type_prefix': self.type_prefix,
                                                  'message': self.message,
                                                  'forum': self.forum,
@@ -203,5 +203,5 @@ class ThreadBaseView(ViewBase):
                                                  'quick_reply': FormFields(QuickReplyForm(request=request)).fields,
                                                  'thread_form': FormFields(self.thread_form).fields if self.thread_form else None,
                                                  'posts_form': FormFields(self.posts_form).fields if self.posts_form else None,
-                                                 },
+                                                 }),
                                                 context_instance=RequestContext(request));

+ 4 - 4
misago/models/forummodel.py

@@ -114,11 +114,11 @@ class ForumManager(models.Manager):
     def readable_forums(self, acl, include_special=False):
         self.populate_tree()
         readable = []
-        for forum in self.forums_tree:
+        for pk, forum in self.forums_tree.items():
             if ((include_special or not forum.special) and 
-                    acl.forums.can_browse(forum.pk) and
-                    acl.threads.acl[forum.pk]['can_read_threads']):
-                readable.append(forum.pk)
+                    acl.forums.can_browse(pk) and
+                    acl.threads.acl[pk]['can_read_threads']):
+                readable.append(pk)
         return readable
 
 

+ 13 - 1
static/cranefly/css/cranefly.css

@@ -852,12 +852,14 @@ a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decor
 .header-primary .breadcrumb li a:hover,.header-primary .breadcrumb li a:active{color:#333333;}
 .header-primary .breadcrumb li .divider{padding-left:0px;padding-right:0px;}.header-primary .breadcrumb li .divider i{opacity:0.2;filter:alpha(opacity=20);position:relative;bottom:1px;}
 .header-primary h1{color:#555555;font-size:35px;font-weight:normal;}
-.header-primary .header-stats{overflow:auto;margin-bottom:0px;color:#999999;}.header-primary .header-stats li{float:left;margin-right:14px;}.header-primary .header-stats li>a{color:#999999;}.header-primary .header-stats li>a:hover,.header-primary .header-stats li>a:active{color:#333333;}
+.header-primary .header-stats{overflow:visible;margin-bottom:0px;color:#999999;}.header-primary .header-stats li{float:left;margin-right:14px;}.header-primary .header-stats li>a{color:#999999;}.header-primary .header-stats li>a:hover,.header-primary .header-stats li>a:active{color:#333333;}
 .header-primary .header-stats li>i{opacity:0.5;filter:alpha(opacity=50);}
+.header-primary .header-stats li.stats-form{float:right;}.header-primary .header-stats li.stats-form form{margin:0px;margin-bottom:-12px;padding:0px;}.header-primary .header-stats li.stats-form form button{position:relative;bottom:12px;}.header-primary .header-stats li.stats-form form button>i{position:relative;top:0px;}
 .header-primary .header-tabs{border-bottom:0px;margin:0px;margin-top:-10px;position:relative;top:9px;}.header-primary .header-tabs li a:link,.header-primary .header-tabs li a:visited{background:none;border:none;border-radius:0px;margin-bottom:4px;padding:6.666666666666667px 10px;color:#888888;font-weight:bold;}
 .header-primary .header-tabs li a:hover,.header-primary .header-tabs li a:active,.header-primary .header-tabs li a a:focus{background:none;border-bottom:4px solid #555555;margin-bottom:0px;color:#555555;}
 .header-primary .header-tabs li.active a:link,.header-primary .header-tabs li.active a:visited,.header-primary .header-tabs li.active a:hover,.header-primary .header-tabs li.active a:active{background:none;border-bottom:4px solid #cf402e;margin-bottom:0px;color:#333333;}
 .header-primary .header-tabs li .form-inline{margin:0px;margin-left:14px;margin-bottom:7px;}.header-primary .header-tabs li .form-inline .btn-icon{padding-left:7px;padding-right:7px;}
+.header-primary .header-tabs li .form-inline i{position:relative;top:0px;}
 html,body{height:100%;}
 #wrap{min-height:100%;height:auto !important;height:100%;margin:0 auto -100px;}#wrap .container-primary{padding-top:20px;padding-bottom:120px;}#wrap .container-primary .page-description{margin-bottom:20px;}
 #wrap .container-primary hr{border:none;border-top:1px solid #eeeeee;}
@@ -1114,6 +1116,16 @@ a.btn-link:hover,a.btn-link:active,a.btn-link:focus{opacity:0.9;filter:alpha(opa
 .thread-quick-reply .editor{margin-left:121px;position:relative;}.thread-quick-reply .editor:after,.thread-quick-reply .editor:before{right:100%;border:solid transparent;content:"";height:0;width:0;position:absolute;pointer-events:none;}
 .thread-quick-reply .editor:after{border-color:transparent;border-right-color:#ffffff;border-width:10.5px;top:14px;margin-top:0px;}
 .thread-quick-reply .editor:before{border-color:transparent;border-right-color:#e6e6e6;border-width:11.5px;top:14px;margin-top:-1px;}
+.thread-participants h3{margin:0px;margin-top:-6px;padding:0px;color:#555555;font-size:17.5px;font-weight:bold;}
+.thread-participants ul{background-color:#ffffff;border:1px solid #e2e2e2;border-radius:3px;margin:0px;margin-bottom:20px;padding:0px;}.thread-participants ul li{border-bottom:1px dotted #e2e2e2;margin:0px;padding:6px 8px;font-weight:bold;}.thread-participants ul li img{background-color:#ffffff;border-radius:2px;width:24px;height:24px;}
+.thread-participants ul li a:link,.thread-participants ul li a:active,.thread-participants ul li a:visited,.thread-participants ul li a:hover{margin:0px 4px;color:#333333;font-weight:bold;}
+.thread-participants ul li:last-child{border-bottom:none;}
+.thread-participants ul li form{float:right;margin:0px;padding:0px;}.thread-participants ul li form button{padding-left:5px;padding-right:5px;}.thread-participants ul li form button i{position:relative;top:1px;}
+.thread-participants h4{margin:0px;padding:0px;color:#555555;font-size:16.8px;font-weight:bold;}
+.thread-participants .no-participants{margin-bottom:20px;}
+.thread-participants .invite-participant{background-color:#ffffff;border:1px solid #d5d5d5;border-radius:3px;margin-top:6px;padding:1px;}.thread-participants .invite-participant form{margin:0px;padding:0px;}.thread-participants .invite-participant form input,.thread-participants .invite-participant form button{border:none;background:none;box-shadow:none;}
+.thread-participants .invite-participant form input{width:70%;}
+.thread-participants .invite-participant form button{float:right;}
 .post-votes-list .vote-user,.post-votes-list .vote-user:link,.post-votes-list .vote-user:visited{color:#555555;font-size:17.5px;font-weight:bold;}
 .post-votes-list .vote-user .vote-icon{background-color:#999999;border-radius:3px;padding:2px 3px;position:relative;bottom:1.75px;font-size:14px;}.post-votes-list .vote-user .vote-icon i{background-image:url("../img/glyphicons-halflings-white.png");}
 .post-votes-list a.vote-user:hover,.post-votes-list a.vote-user:active{color:#333333;text-decoration:none;}

+ 26 - 1
static/cranefly/css/cranefly/header.less

@@ -47,7 +47,7 @@
   }
 
   .header-stats {
-    overflow: auto;
+    overflow: visible;
     margin-bottom: 0px;
 
     color: @grayLight;
@@ -67,6 +67,26 @@
       &>i {
         .opacity(50);
       }
+
+      &.stats-form {
+        float: right;
+
+        form {
+          margin: 0px;
+          margin-bottom: -12px;
+          padding: 0px;
+
+          button {
+            position: relative;
+            bottom: 12px;
+
+            &>i {
+              position: relative;
+              top: 0px;
+            }
+          }
+        }
+      }
     }
   }
 
@@ -118,6 +138,11 @@
           padding-left: 7px;
           padding-right: 7px;
         }
+
+        i {
+          position: relative;
+          top: 0px;
+        }
       }
     }
   }

+ 104 - 0
static/cranefly/css/cranefly/thread.less

@@ -455,3 +455,107 @@
     }
   }
 }
+
+// Thread participants list
+.thread-participants {
+  h3 {
+    margin: 0px;
+    margin-top: (@baseLineHeight - @baseFontSize) * -1;
+    padding: 0px;
+
+    color: @gray;
+    font-size: @fontSizeLarge;
+    font-weight: bold;
+  }
+
+  ul {
+    background-color: @white;
+    border: 1px solid darken(@bodyBackground, 10%);
+    border-radius: @baseBorderRadius;
+    margin: 0px;
+    margin-bottom: @baseLineHeight;
+    padding: 0px;
+
+    li {
+      border-bottom: 1px dotted darken(@bodyBackground, 10%);
+      margin: 0px;
+      padding: 6px 8px;
+
+      font-weight: bold;
+
+      img {
+        background-color: @white;
+        border-radius: @borderRadiusSmall;
+        width: 24px;
+        height: 24px;
+      }
+
+      a:link, a:active, a:visited, a:hover {
+        margin: 0px 4px;
+
+        color: @textColor;
+        font-weight: bold;
+      }
+
+      &:last-child {
+        border-bottom: none;
+      }
+
+      form {
+        float: right;
+        margin: 0px;
+        padding: 0px;
+
+        button {
+          padding-left: 5px;
+          padding-right: 5px;
+
+          i {
+            position: relative;
+            top: 1px;
+          }
+        }
+      }
+    }
+  }
+
+  h4 {
+    margin: 0px;
+    padding: 0px;
+
+    color: @gray;
+    font-size: @baseFontSize * 1.2;
+    font-weight: bold;
+  }
+
+  .no-participants {
+    margin-bottom: @baseLineHeight;
+  }
+
+  .invite-participant {
+    background-color: @white;
+    border: 1px solid darken(@bodyBackground, 15%);
+    border-radius: @baseBorderRadius;
+    margin-top: @baseLineHeight - @baseFontSize;
+    padding: 1px;
+
+    form {
+      margin: 0px;
+      padding: 0px;
+
+      input, button {
+        border: none;
+        background: none;
+        box-shadow: none;
+      }
+
+      input {
+        width: 70%;
+      }
+
+      button {
+        float: right;
+      }
+    }
+  }
+}

+ 1 - 1
templates/cranefly/index.html

@@ -52,7 +52,7 @@
         <ul class="unstyled">
           {% for online in rank.online %}
           <li>
-            <img src="{{ online.get_avatar(48) }}" alt="" class="avatar-small">
+            <img src="{{ online.get_avatar(24) }}" alt="" class="avatar-small">
             <a href="{% url 'user' username=online.username_slug, user=online.pk %}">{{ online.username }}</a>
             {% if rank.title or online.title %}<span class="label">{% if online.title %}{{ online.title }}{% else %}{{ _(rank.title) }}{% endif %}</span>{% endif %}
           </li>

+ 337 - 290
templates/cranefly/private_threads/thread.html

@@ -27,6 +27,11 @@
       {%- else -%}
         {% trans %}No replies{% endtrans %}
       {%- endif %}</li>
+      <li class="stats-form">
+        <form action="" method="post">
+          <button type="submit" class="btn"><i class="icon-remove"></i> Leave Thread</button>
+        </form>
+      </li>
     </ul>
   </div>
 </div>
@@ -38,320 +43,362 @@
   </div>
   {% endif %}
 
-  <div class="thread-buttons">
-    {{ pager() }} 
-    {% if acl.threads.can_reply(forum, thread) %}
-    <a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
-    {% endif %}
-    {% if watcher %}
-    <form action="{% url 'private_thread_unwatch' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-success tooltip-top" title="{% trans %}Remove thread from watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
-    {% if watcher.email %}
-    <form action="{% url 'private_thread_unwatch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-success tooltip-top" title="{% trans %}Don't e-mail me anymore if anyone replies to this thread{% endtrans %}"><i class="icon-envelope"></i></button></form>
-    {% else %}
-    <form action="{% url 'private_thread_watch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}E-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
-    {% endif %}
-    {% else %}
-    <form action="{% url 'private_thread_watch' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}Add thread to watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
-    <form action="{% url 'private_thread_watch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}Add thread to watched list and e-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
-    {% endif %}
-    {% if ignored_posts %}
-    <form action="{% url 'private_thread_show_hidden' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><button type="submit" class="btn"><i class="icon-eye-open"></i> {% trans %}Show Hidden Replies{% endtrans %}</button></form>
-    {% endif %}
-  </div>
+  <div class="row">
+    <div class="span9">
 
-  <div class="thread-body">
-    {% for post in posts %}
-    <div id="post-{{ post.pk }}" class="post-wrapper">
-      {% if post.message %}
-      <div class="messages-list">
-        {{ macros.draw_message(post.message) }}
-      </div>
-      {% endif %}
-      {% if post.deleted and not acl.threads.can_see_deleted_posts(forum) %}
-      <div class="post-body post-muted">
-        {% if post.user_id %}
-        <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}"><img src="{{ post.user.get_avatar(50) }}" alt="" class="user-avatar"></a>
+      <div class="thread-buttons">
+        {{ pager() }} 
+        {% if acl.threads.can_reply(forum, thread) and participants|length > 1 %}
+        <a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
+        {% endif %}
+        {% if watcher %}
+        <form action="{% url 'private_thread_unwatch' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-success tooltip-top" title="{% trans %}Remove thread from watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
+        {% if watcher.email %}
+        <form action="{% url 'private_thread_unwatch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn btn-success tooltip-top" title="{% trans %}Don't e-mail me anymore if anyone replies to this thread{% endtrans %}"><i class="icon-envelope"></i></button></form>
         {% else %}
-        <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar"></a>
+        <form action="{% url 'private_thread_watch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}E-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
+        {% endif %}
+        {% else %}
+        <form action="{% url 'private_thread_watch' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}Add thread to watched list{% endtrans %}"><i class="icon-bookmark"></i></button></form>
+        <form action="{% url 'private_thread_watch_email' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><input type="hidden" name="retreat" value="{{ request_path }}"><button type="submit" class="btn tooltip-top" title="{% trans %}Add thread to watched list and e-mail me if anyone replies{% endtrans %}"><i class="icon-envelope"></i></button></form>
+        {% endif %}
+        {% if ignored_posts %}
+        <form action="{% url 'private_thread_show_hidden' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post"><input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}"><button type="submit" class="btn"><i class="icon-eye-open"></i> {% trans %}Show Hidden Replies{% endtrans %}</button></form>
         {% endif %}
-        <div class="post-content">
-          <div class="post-header">
-            <div class="post-header-compact">
-              {% if post.user_id %}
-              <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
-              {% else %}
-              <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
-              {% endif %}
-              <span class="separator">&ndash;</span>
-              <a href="{% if pagination['page'] > 1 -%}
-              {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-              {%- else -%}
-              {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-              {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
-              {% if post.edits %}
-              <span class="separator">&ndash;</span>
-              {% if acl.threads.can_see_changelog(user, forum, post) %}
-              <a href="{% url 'changelog' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</a>
-              {% else %}
-              <span class="post-changelog">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</span>
-              {% endif %}
-              {% endif %}
-            </div>
-
-            <a href="{% if pagination['page'] > 1 -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-            {%- else -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-            {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
-
-            {% if not post.is_read %}
-            <div class="post-extra">
-              <span class="label label-warning">
-                {% trans %}New{% endtrans %}
-              </span>
-            </div>
-            {% endif %}
-
-          </div>
-          <div class="post-message">
-            {% trans user=edit_user(post), date=post.edit_date|reltimesince|low %}{{ user }} has deleted this reply {{ date }}{% endtrans %}
-          </div>
-        </dv>
       </div>
-      {% elif post.ignored %}
-      <div class="post-body post-muted">
-        <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar"></a>
-        <div class="post-arrow"></div>
-        <div class="post-content">
-          <div class="post-header">
-            <div class="post-header-compact">
-              <a href="{% if pagination['page'] > 1 -%}
-              {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-              {%- else -%}
-              {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-              {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
-            </div>
 
-            <a href="{% if pagination['page'] > 1 -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-            {%- else -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-            {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
-
-            {% if not post.is_read %}
-            <div class="post-extra">
-              <span class="label label-warning">
-                {% trans %}New{% endtrans %}
-              </span>
-            </div>
-            {% endif %}
-
-          </div>
-          <div class="post-message">
-            {% trans %}This reply was posted by user that is on your ignored list.{% endtrans %}
+      <div class="thread-body">
+        {% for post in posts %}
+        <div id="post-{{ post.pk }}" class="post-wrapper">
+          {% if post.message %}
+          <div class="messages-list">
+            {{ macros.draw_message(post.message) }}
           </div>
-        </dv>
-      </div>
-      {% else %}
-      <div class="post-body">
-        {% if post.user_id %}
-        <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}"><img src="{{ post.user.get_avatar(100) }}" alt="" class="user-avatar"></a>
-        {% else %}
-        <img src="{{ macros.avatar_guest(100) }}" alt="" class="user-avatar"></a>
-        {% endif %}
-        <div class="post-arrow"></div>
-        <div class="post-content">
-          <div class="post-header">
+          {% endif %}
+          {% if post.deleted and not acl.threads.can_see_deleted_posts(forum) %}
+          <div class="post-body post-muted">
             {% if post.user_id %}
-            <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
-            {% else %}
-            <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
-            {% endif %}
-            <span class="separator">&ndash;</span>
-            <a href="{% if pagination['page'] > 1 -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-            {%- else -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-            {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
-            {% if post.edits %}
-            <span class="separator">&ndash;</span>
-            {% if acl.threads.can_see_changelog(user, forum, post) %}
-            <a href="{% url 'private_thread_changelog' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</a>
+            <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}"><img src="{{ post.user.get_avatar(50) }}" alt="" class="user-avatar"></a>
             {% else %}
-            <span class="post-changelog">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</span>
-            {% endif %}
+            <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar"></a>
             {% endif %}
+            <div class="post-content">
+              <div class="post-header">
+                <div class="post-header-compact">
+                  {% if post.user_id %}
+                  <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
+                  {% else %}
+                  <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
+                  {% endif %}
+                  <span class="separator">&ndash;</span>
+                  <a href="{% if pagination['page'] > 1 -%}
+                  {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                  {%- else -%}
+                  {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                  {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
+                  {% if post.edits %}
+                  <span class="separator">&ndash;</span>
+                  {% if acl.threads.can_see_changelog(user, forum, post) %}
+                  <a href="{% url 'changelog' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</a>
+                  {% else %}
+                  <span class="post-changelog">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</span>
+                  {% endif %}
+                  {% endif %}
+                </div>
+
+                <a href="{% if pagination['page'] > 1 -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                {%- else -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
+
+                {% if not post.is_read %}
+                <div class="post-extra">
+                  <span class="label label-warning">
+                    {% trans %}New{% endtrans %}
+                  </span>
+                </div>
+                {% endif %}
 
-            {% if posts_form %}
-            <label class="checkbox post-checkbox"><input form="posts_form" name="{{ posts_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ post.pk }}"{% if posts_form['list_items']['has_value'] and ('' ~ post.pk) in posts_form['list_items']['value'] %} checked="checked"{% endif %}></label>
-            {% endif %}
+              </div>
+              <div class="post-message">
+                {% trans user=edit_user(post), date=post.edit_date|reltimesince|low %}{{ user }} has deleted this reply {{ date }}{% endtrans %}
+              </div>
+            </dv>
+          </div>
+          {% elif post.ignored %}
+          <div class="post-body post-muted">
+            <img src="{{ macros.avatar_guest(60) }}" alt="" class="user-avatar"></a>
+            <div class="post-arrow"></div>
+            <div class="post-content">
+              <div class="post-header">
+                <div class="post-header-compact">
+                  <a href="{% if pagination['page'] > 1 -%}
+                  {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                  {%- else -%}
+                  {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                  {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
+                </div>
+
+                <a href="{% if pagination['page'] > 1 -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                {%- else -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
+
+                {% if not post.is_read %}
+                <div class="post-extra">
+                  <span class="label label-warning">
+                    {% trans %}New{% endtrans %}
+                  </span>
+                </div>
+                {% endif %}
 
-            <a href="{% if pagination['page'] > 1 -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
-            {%- else -%}
-            {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
-            {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
-
-            <div class="post-extra">
-              {% if post.protected and acl.threads.can_protect(forum) %}
-              <span class="label label-info">
-                {% trans %}Protected{% endtrans %}
-              </span>
-              {% endif %}
-
-              {% if post.deleted %}
-              <span class="label label-inverse">
-                {% trans %}Deleted{% endtrans %}
-              </span>
-              {% endif %}
-
-              {% if post.moderated %}
-              <span class="label label-purple">
-                {% trans %}Unreviewed{% endtrans %}
-              </span>
-              {% endif %}
-
-              {% if post.reported %}
-              <span class="label label-important">
-                {% trans %}Reported{% endtrans %}
-              </span>
-              {% endif %}
-
-              {% if not post.is_read %}
-              <span class="label label-warning">
-                {% trans %}New{% endtrans %}
-              </span>
-              {% endif %}
-            </div>
+              </div>
+              <div class="post-message">
+                {% trans %}This reply was posted by user that is on your ignored list.{% endtrans %}
+              </div>
+            </dv>
           </div>
-          <div class="post-message">
-            <div class="markdown js-extra">
-              {{ post.post_preparsed|markdown_final|safe }}
-            </div>
-            {% if post.user.signature %}
-            <div class="post-signature">
-              <div class="markdown">
-                {{ post.user.signature_preparsed|markdown_final|safe }}
+          {% else %}
+          <div class="post-body">
+            {% if post.user_id %}
+            <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}"><img src="{{ post.user.get_avatar(100) }}" alt="" class="user-avatar"></a>
+            {% else %}
+            <img src="{{ macros.avatar_guest(100) }}" alt="" class="user-avatar"></a>
+            {% endif %}
+            <div class="post-arrow"></div>
+            <div class="post-content">
+              <div class="post-header">
+                {% if post.user_id %}
+                <a href="{% url 'user' user=post.user.pk, username=post.user.username_slug %}" class="post-author">{{ post.user.username }}</a>{% if post.user.get_title() %} {{ user_label(post.user) }}{% endif %}
+                {% else %}
+                <span class="post-author">{{ post.user_name }}</span> <span class="label post-author-label post-label-guest">{% trans %}Unregistered{% endtrans %}</span>
+                {% endif %}
+                <span class="separator">&ndash;</span>
+                <a href="{% if pagination['page'] > 1 -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                {%- else -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                {%- endif %}#post-{{ post.pk }}" class="post-date">{{ post.date|reltimesince }}</a>
+                {% if post.edits %}
+                <span class="separator">&ndash;</span>
+                {% if acl.threads.can_see_changelog(user, forum, post) %}
+                <a href="{% url 'private_thread_changelog' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-changelog tooltip-bottom" title="{% trans %}Show changelog{% endtrans %}">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</a>
+                {% else %}
+                <span class="post-changelog">{% trans count=post.edits %}One edit{% pluralize %}{{ count }} edits{% endtrans %}</span>
+                {% endif %}
+                {% endif %}
+
+                {% if posts_form %}
+                <label class="checkbox post-checkbox"><input form="posts_form" name="{{ posts_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ post.pk }}"{% if posts_form['list_items']['has_value'] and ('' ~ post.pk) in posts_form['list_items']['value'] %} checked="checked"{% endif %}></label>
+                {% endif %}
+
+                <a href="{% if pagination['page'] > 1 -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug, page=pagination['page'] %}
+                {%- else -%}
+                {% url 'private_thread' thread=thread.pk, slug=thread.slug %}
+                {%- endif %}#post-{{ post.pk }}" class="post-perma tooltip-left" title="{% trans %}Direct link to this post{% endtrans %}">#{{ pagination['start'] + loop.index }}</a>
+
+                <div class="post-extra">
+                  {% if post.protected and acl.threads.can_protect(forum) %}
+                  <span class="label label-info">
+                    {% trans %}Protected{% endtrans %}
+                  </span>
+                  {% endif %}
+
+                  {% if post.deleted %}
+                  <span class="label label-inverse">
+                    {% trans %}Deleted{% endtrans %}
+                  </span>
+                  {% endif %}
+
+                  {% if post.moderated %}
+                  <span class="label label-purple">
+                    {% trans %}Unreviewed{% endtrans %}
+                  </span>
+                  {% endif %}
+
+                  {% if post.reported %}
+                  <span class="label label-important">
+                    {% trans %}Reported{% endtrans %}
+                  </span>
+                  {% endif %}
+
+                  {% if not post.is_read %}
+                  <span class="label label-warning">
+                    {% trans %}New{% endtrans %}
+                  </span>
+                  {% endif %}
+                </div>
+              </div>
+              <div class="post-message">
+                <div class="markdown js-extra">
+                  {{ post.post_preparsed|markdown_final|safe }}
+                </div>
+                {% if post.user.signature %}
+                <div class="post-signature">
+                  <div class="markdown">
+                    {{ post.user.signature_preparsed|markdown_final|safe }}
+                  </div>
+                </div>
+                {% endif %}
               </div>
+              <div class="post-footer">{% filter trim %}
+                <div class="post-actions">              
+                  {% if acl.users.can_see_users_trails() -%}
+                  <a href="{% url 'private_post_info' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-trail">{% trans %}Info{% endtrans %}</a>
+                  {% endif %}
+                  {% if acl.threads.can_edit_thread(user, forum, thread, post) and thread.start_post_id == post.pk %}
+                  <a href="{% url 'private_thread_edit' thread=thread.pk, slug=thread.slug %}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
+                  {% elif acl.threads.can_edit_reply(user, forum, thread, post) %}
+                  <a href="{% url 'private_post_edit' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
+                  {%- endif %}
+                  {% if acl.threads.can_reply(forum, thread) %}<a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug, quote=post.pk %}" class="post-reply">{% trans %}Reply{% endtrans %}</a>{% endif %}
+                </div>
+                {% if post.pk == thread.start_post_id %}
+                <div class="post-actions">
+                  {% if acl.threads.can_delete_thread(user, forum, thread, post) == 2 %}
+                  <form action="{% url 'private_thread_delete' thread=thread.pk, slug=thread.slug %}" class="form-inline prompt-delete-thread" method="post">
+                    <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+                    <span>{% trans %}Delete thread:{% endtrans %}</span>
+                    <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this thread for good{% endtrans %}">{% trans %}Hard{% endtrans %}</button>
+                  </form>
+                  {% endif %}
+                  {% if not post.deleted and acl.threads.can_delete_thread(user, forum, thread, post) %}
+                  <form action="{% url 'private_thread_hide' thread=thread.pk, slug=thread.slug %}" class="form-inline prompt-delete-thread" method="post">
+                    <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Hide this thread from other users{% endtrans %}">{% trans %}Soft{% endtrans %}</button>
+                    <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+                  </form>
+                  {% endif %}
+                </div>
+                {% elif post.pk != thread.start_post_id and acl.threads.can_delete_post(user, forum, thread, post) %}
+                <div class="post-actions">
+                  {% if acl.threads.can_delete_post(user, forum, thread, post) == 2 -%}
+                  <form action="{% url 'private_post_delete' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="form-inline prompt-delete-post" method="post">
+                    <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+                    <span>{% trans %}Delete reply:{% endtrans %}</span>
+                    <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this reply for good{% endtrans %}">{% trans %}Hard{% endtrans %}</button>
+                  </form>
+                  {% endif %}
+                  {% if not post.deleted and acl.threads.can_delete_post(user, forum, thread, post) %}
+                  <form action="{% url 'private_post_hide' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="form-inline prompt-delete-post" method="post">
+                    <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+                    <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Hide this reply from other users{% endtrans %}">{% trans %}Soft{% endtrans %}</button>
+                  </form>
+                  {% endif %}
+                </div>
+                {% endif %}
+              {% endfilter %}</div>
             </div>
-            {% endif %}
           </div>
-          <div class="post-footer">{% filter trim %}
-            <div class="post-actions">              
-              {% if acl.users.can_see_users_trails() -%}
-              <a href="{% url 'private_post_info' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-trail">{% trans %}Info{% endtrans %}</a>
-              {% endif %}
-              {% if acl.threads.can_edit_thread(user, forum, thread, post) and thread.start_post_id == post.pk %}
-              <a href="{% url 'private_thread_edit' thread=thread.pk, slug=thread.slug %}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
-              {% elif acl.threads.can_edit_reply(user, forum, thread, post) %}
-              <a href="{% url 'private_post_edit' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="post-edit">{% trans %}Edit{% endtrans %}</a>
-              {%- endif %}
-              {% if acl.threads.can_reply(forum, thread) %}<a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug, quote=post.pk %}" class="post-reply">{% trans %}Reply{% endtrans %}</a>{% endif %}
-            </div>
-            {% if post.pk == thread.start_post_id %}
-            <div class="post-actions">
-              {% if acl.threads.can_delete_thread(user, forum, thread, post) == 2 %}
-              <form action="{% url 'private_thread_delete' thread=thread.pk, slug=thread.slug %}" class="form-inline prompt-delete-thread" method="post">
-                <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-                <span>{% trans %}Delete thread:{% endtrans %}</span>
-                <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this thread for good{% endtrans %}">{% trans %}Hard{% endtrans %}</button>
-              </form>
-              {% endif %}
-              {% if not post.deleted and acl.threads.can_delete_thread(user, forum, thread, post) %}
-              <form action="{% url 'private_thread_hide' thread=thread.pk, slug=thread.slug %}" class="form-inline prompt-delete-thread" method="post">
-                <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Hide this thread from other users{% endtrans %}">{% trans %}Soft{% endtrans %}</button>
-                <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-              </form>
-              {% endif %}
-            </div>
-            {% elif post.pk != thread.start_post_id and acl.threads.can_delete_post(user, forum, thread, post) %}
-            <div class="post-actions">
-              {% if acl.threads.can_delete_post(user, forum, thread, post) == 2 -%}
-              <form action="{% url 'private_post_delete' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="form-inline prompt-delete-post" method="post">
-                <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-                <span>{% trans %}Delete reply:{% endtrans %}</span>
-                <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Delete this reply for good{% endtrans %}">{% trans %}Hard{% endtrans %}</button>
-              </form>
-              {% endif %}
-              {% if not post.deleted and acl.threads.can_delete_post(user, forum, thread, post) %}
-              <form action="{% url 'private_post_hide' thread=thread.pk, slug=thread.slug, post=post.pk %}" class="form-inline prompt-delete-post" method="post">
-                <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-                <button type="submit" class="btn btn-link tooltip-top" title="{% trans %}Hide this reply from other users{% endtrans %}">{% trans %}Soft{% endtrans %}</button>
-              </form>
-              {% endif %}
-            </div>
-            {% endif %}
-          {% endfilter %}</div>
+          {% endif %}
+        </div>
+
+        {% if post.checkpoint_set.all() %}
+        <div class="post-checkpoints">
+          {% for checkpoint in post.checkpoint_set.all() %}
+          <div class="post-checkpoint">
+            <hr>
+            <span>
+              {%- if checkpoint.action == 'limit' -%}
+              <i class="icon-lock"></i> {% trans  %}This thread has reached its post limit and has been closed.{% endtrans %}
+              {%- elif checkpoint.action == 'accepted' -%}
+              <i class="icon-ok"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} accepted this thread {{ date }}{% endtrans %}
+              {%- elif checkpoint.action == 'closed' -%}
+              <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} closed this thread {{ date }}{% endtrans %}
+              {%- elif checkpoint.action == 'opened' -%}
+              <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} opened this thread {{ date }}{% endtrans %}
+              {%- elif checkpoint.action == 'deleted' -%}
+              <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} deleted this thread {{ date }}{% endtrans %}
+              {%- elif checkpoint.action == 'undeleted' -%}
+              <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} restored this thread {{ date }}{% endtrans %}
+              {%- endif -%}
+            </span>
+          </div>
+          {% endfor %}
         </div>
+        {% endif %}
+        {% endfor %}
+      </div>
+
+      {% if thread_form or posts_form %}
+      <div class="thread-moderation">
+        {% if thread_form%}
+        <form id="thread_form" class="form-inline pull-left" action="{% url 'private_thread' slug=thread.slug, thread=thread.id, page=pagination['page'] %}" method="POST">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <input type="hidden" name="origin" value="thread_form">
+          {{ form_theme.input_select(thread_form['thread_action'],width=3) }}
+          <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
+        </form>
+        {% endif %}
+        {% if posts_form%}
+        <form id="posts_form" class="form-inline pull-right" action="{% url 'private_thread' slug=thread.slug, thread=thread.id, page=pagination['page'] %}" method="POST">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <input type="hidden" name="origin" value="posts_form">
+          {{ form_theme.input_select(posts_form['list_action'],width=3) }}
+          <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
+        </form>
+        {% endif %}
       </div>
       {% endif %}
-    </div>
 
-    {% if post.checkpoint_set.all() %}
-    <div class="post-checkpoints">
-      {% for checkpoint in post.checkpoint_set.all() %}
-      <div class="post-checkpoint">
-        <hr>
-        <span>
-          {%- if checkpoint.action == 'limit' -%}
-          <i class="icon-lock"></i> {% trans  %}This thread has reached its post limit and has been closed.{% endtrans %}
-          {%- elif checkpoint.action == 'accepted' -%}
-          <i class="icon-ok"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} accepted this thread {{ date }}{% endtrans %}
-          {%- elif checkpoint.action == 'closed' -%}
-          <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} closed this thread {{ date }}{% endtrans %}
-          {%- elif checkpoint.action == 'opened' -%}
-          <i class="icon-lock"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} opened this thread {{ date }}{% endtrans %}
-          {%- elif checkpoint.action == 'deleted' -%}
-          <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} deleted this thread {{ date }}{% endtrans %}
-          {%- elif checkpoint.action == 'undeleted' -%}
-          <i class="icon-trash"></i> {% trans user=checkpoint_user(checkpoint), date=checkpoint.date|reltimesince|low %}{{ user }} restored this thread {{ date }}{% endtrans %}
-          {%- endif -%}
-        </span>
+      <div class="thread-buttons">
+        {{ pager(false) }}
+        {% if acl.threads.can_reply(forum, thread) and participants|length > 1 %}
+        <a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
+        {% else %}
+        <p class="lead thread-signin-message">{% trans %}This thread has no participants.{% endtrans %}</p>
+        {% endif %}
       </div>
-      {% endfor %}
-    </div>
-    {% endif %}
-    {% endfor %}
-  </div>
 
-  {% if thread_form or posts_form %}
-  <div class="thread-moderation">
-    {% if thread_form%}
-    <form id="thread_form" class="form-inline pull-left" action="{% url 'private_thread' slug=thread.slug, thread=thread.id, page=pagination['page'] %}" method="POST">
-      <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-      <input type="hidden" name="origin" value="thread_form">
-      {{ form_theme.input_select(thread_form['thread_action'],width=3) }}
-      <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
-    </form>
-    {% endif %}
-    {% if posts_form%}
-    <form id="posts_form" class="form-inline pull-right" action="{% url 'private_thread' slug=thread.slug, thread=thread.id, page=pagination['page'] %}" method="POST">
-      <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-      <input type="hidden" name="origin" value="posts_form">
-      {{ form_theme.input_select(posts_form['list_action'],width=3) }}
-      <button type="submit" class="btn btn-danger">{% trans %}Go{% endtrans %}</button>
-    </form>
-    {% endif %}
-  </div>
-  {% endif %}
+      {% if acl.threads.can_reply(forum, thread) and participants|length > 1 %}
+      <div class="thread-quick-reply">
+        <form action="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" method="post">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <input type="hidden" name="quick_reply" value="1">
+          <img src="{{ user.get_avatar(100) }}" alt="{% trans %}Your Avatar{% endtrans %}" class="user-avatar">
+          {{ editor.editor(quick_reply.post, _('Post Reply'), extra=editor_extra()) }}
+        </form>
+      </div>
+      {% endif %}
 
-  <div class="thread-buttons">
-    {{ pager(false) }}
-    {% if acl.threads.can_reply(forum, thread) %}
-    <a href="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" class="btn btn-inverse pull-right"><i class="icon-pencil"></i> {% trans %}Reply{% endtrans %}</a>
-    {% endif %}
-  </div>
+    </div>
+    <div class="span3">
+      <div class="thread-participants">
+        <h3>{% trans count=participants|length -%}
+          One participant
+          {%- pluralize -%}
+          {{ count }} participants
+          {%- endtrans %}</h3>
+        <ul class="unstyled">{% for participant in participants %}
+          <li>
+            <img src="{{ participant.get_avatar(24) }}" alt="" class="avatar-small">
+            <a href="{% url 'user' username=participant.username_slug, user=participant.pk %}">{{ participant.username }}</a>
+            {% if user.pk == thread.start_poster_id %}
+            <form class="form-inline" action="" method="post">
+              <button type="submit" class="btn btn-{% if participant.pk == user.pk %}danger{% else %}inverse{% endif %} btn-small tooltip-left" title="{% if participant.pk == user.pk %}{% trans %}Leave this thread{% endtrans %}{% else %}{% trans %}Remove from this thread{% endtrans %}{% endif %}"><i class="icon-remove"></i></button>
+            </form>
+            {% endif %}
+          </li>
+          {% endfor %}
+        </ul>
 
-  {% if acl.threads.can_reply(forum, thread) %}
-  <div class="thread-quick-reply">
-    <form action="{% url 'private_thread_reply' thread=thread.pk, slug=thread.slug %}" method="post">
-      <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-      <input type="hidden" name="quick_reply" value="1">
-      <img src="{{ user.get_avatar(100) }}" alt="{% trans %}Your Avatar{% endtrans %}" class="user-avatar">
-      {{ editor.editor(quick_reply.post, _('Post Reply'), extra=editor_extra()) }}
-    </form>
+        {% if participants|length < 2%}
+        <p class="no-participants">{% trans %}This thread has too few participants. Invite other users to open it for new replies.{% endtrans %}</p>
+        {% endif %}
+
+        <h4>{% trans %}Invite User{% endtrans %}</h4>
+        <div class="invite-participant">
+          <form class="form-inline">
+            <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+            {{ form_theme.input_text(invite_form.fields.username, width="2", attrs={'placeholder':_("User to invite...")}) }}
+            <button class="btn" type="submit"><i class="icon-plus"></i></button>
+          </form>
+        </div>
+      </div>
+    </div>
   </div>
-  {% endif %}
 
 </div>
 {% endblock %}