← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands-website/hidden_topics into lp:widelands-website

 

kaputtnik has proposed merging lp:~widelands-dev/widelands-website/hidden_topics into lp:widelands-website.

Commit message:
Implement possibility to hide whole topics

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands-website/hidden_topics/+merge/358944

Implement possibility to hide whole topics. The hiding is done by hiding the first post of a topic. This is implemented as follows:

- Beside the buttons "Stick Topic"/"Close Topic" an additional button "Toggle Visibility" was added, this button is only shown for forum moderators or superusers

- Showing hidden topics or it's last post is prevented in all forum related pages, like forum categories, in the "Latest Post" box and the Feeds

- Moderators can see hidden topics ONLY in a forums list of topics as a row showing "Hidden Topic: topics_name", and can enter this topic to toggle visibility. In all other places showing hidden topics, or the last post of a hidden topic is prevented

- Because topics are hidden also if it was caught by our spam filter, an additional sentence is shown if this topic was caught by the spam filter.

- If one try's to open a hidden topic by URL (e.g. by a link in another topic), a page with an explanation is shown.

Spam posts appended to an existing topics are now shown for moderators and superusers with a grayish background. For all other users they are not shown.

Showing the forums categories is much faster now by preventing unneeded queries to the database.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands-website/hidden_topics into lp:widelands-website.
=== added file 'media/forum/img/topic_hide.png'
Binary files media/forum/img/topic_hide.png	1970-01-01 00:00:00 +0000 and media/forum/img/topic_hide.png	2018-11-17 11:25:00 +0000 differ
=== added file 'media/forum/img/topic_show.png'
Binary files media/forum/img/topic_show.png	1970-01-01 00:00:00 +0000 and media/forum/img/topic_show.png	2018-11-17 11:25:00 +0000 differ
=== modified file 'pybb/feeds.py'
--- pybb/feeds.py	2018-09-12 07:45:35 +0000
+++ pybb/feeds.py	2018-11-17 11:25:00 +0000
@@ -56,10 +56,10 @@
     title_template = 'pybb/feeds/posts_title.html'
     description_template = 'pybb/feeds/posts_description.html'
 
-    all_objects = Post.objects.filter(hidden=False)
+    all_objects = Post.objects.exclude(topic__in=Post.hidden_topics.all()).filter(hidden=False)
 
     def items_for_object(self, obj):
-        return Post.objects.filter(hidden=False, topic__forum=obj).order_by('-created')[:15]
+        return Post.objects.exclude(topic__in=Post.hidden_topics.all()).filter(hidden=False, topic__forum=obj).order_by('-created')[:15]
 
 # Validated through http://validator.w3.org/feed/
 

=== modified file 'pybb/models.py'
--- pybb/models.py	2018-10-03 09:01:09 +0000
+++ pybb/models.py	2018-11-17 11:25:00 +0000
@@ -17,6 +17,8 @@
 from django.conf import settings
 from notification.models import send
 from django.contrib.auth.models import User
+from check_input.models import SuspiciousInput
+
 
 try:
     from notification import models as notification
@@ -91,8 +93,16 @@
 
     @property
     def last_post(self):
-        posts = self.posts.exclude(hidden=True).order_by(
+        # This is performanter than using the posts manager hidden_topics
+        # We search only for the last 10 topics
+        topics = self.topics.order_by('-updated')[:10]
+        for topic in topics:
+            if topic.is_hidden:
+                continue
+            posts = topic.posts.exclude(hidden=True).order_by(
             '-created').select_related()
+            break
+
         try:
             return posts[0]
         except IndexError:
@@ -122,21 +132,22 @@
 
     @property
     def head(self):
-        return self.posts.all().order_by('created').select_related()[0]
+        try:
+            return self.posts.all().order_by('created').select_related()[0]
+        except:
+            return None
 
     @property
     def last_post(self):
         return self.posts.exclude(hidden=True).order_by('-created').select_related()[0]
 
-    # If the first post of this topic is hidden, the topic is hidden
     @property
     def is_hidden(self):
+        # If the first post of this topic is hidden, the topic is hidden
         try:
-            p = self.posts.order_by('created').filter(
-                hidden=False).select_related()[0]
-        except IndexError:
-            return True
-        return False
+            return self.posts.first().hidden
+        except:
+            return False
 
     @property
     def post_count(self):
@@ -191,6 +202,30 @@
         self.body_html = urlize(self.body_html)
 
 
+class HiddenTopicsManager(models.Manager):
+    """Find all hidden topics by posts.
+
+    A whole topic is hidden, if the first post is hidden.
+    This manager returns the hidden topics and can be used to filter them out
+    like so:
+
+    Post.objects.exclude(topic__in=Post.hidden_topics.all()).filter(...)
+
+    Use this with caution, because it effects performance, see:
+    https://docs.djangoproject.com/en/dev/ref/models/querysets/#in
+    """
+
+    def get_queryset(self, *args, **kwargs):
+        qs = super(HiddenTopicsManager,
+                   self).get_queryset().filter(hidden=True)
+
+        hidden_topics = []
+        for post in qs:
+            if post.topic.is_hidden:
+                hidden_topics.append(post.topic)
+        return hidden_topics
+
+
 class Post(RenderableItem):
     topic = models.ForeignKey(
         Topic, related_name='posts', verbose_name=_('Topic'))
@@ -205,6 +240,9 @@
     body_text = models.TextField(_('Text version'))
     hidden = models.BooleanField(_('Hidden'), blank=True, default=False)
 
+    objects = models.Manager() # Normal manager 
+    hidden_topics = HiddenTopicsManager() # Custom manager
+
     class Meta:
         ordering = ['created']
         verbose_name = _('Post')
@@ -260,6 +298,14 @@
         if self_id == head_post_id:
             self.topic.delete()
 
+    def is_spam(self):
+        try:
+            SuspiciousInput.objects.get(object_id = self.pk)
+            return True
+        except:
+            pass
+        return False
+
 
 class Read(models.Model):
     """For each topic that user has entered the time is logged to this

=== modified file 'pybb/templatetags/pybb_extras.py'
--- pybb/templatetags/pybb_extras.py	2018-09-11 20:16:31 +0000
+++ pybb/templatetags/pybb_extras.py	2018-11-17 11:25:00 +0000
@@ -82,14 +82,17 @@
 
 @register.inclusion_tag('pybb/last_posts.html', takes_context=True)
 def pybb_last_posts(context, number=8):
+
     last_posts = Post.objects.filter(hidden=False).order_by(
         '-created').select_related()[:45]
+
     check = []
     answer = []
     for post in last_posts:
-        if (post.topic_id not in check) and len(check) < number:
-            check = check + [post.topic_id]
-            answer = answer + [post]
+        if not post.topic.is_hidden:
+            if (post.topic_id not in check) and len(check) < number:
+                check = check + [post.topic_id]
+                answer = answer + [post]
     return {
         'posts': answer,
     }

=== modified file 'pybb/urls.py'
--- pybb/urls.py	2018-04-08 15:20:01 +0000
+++ pybb/urls.py	2018-11-17 11:25:00 +0000
@@ -30,6 +30,8 @@
         views.close_topic, name='pybb_close_topic'),
     url('^topic/(?P<topic_id>\d+)/open/$',
         views.open_topic, name='pybb_open_topic'),
+    url('^topic/(?P<topic_id>\d+)/unhide/$',
+        views.toggle_hidden_topic, name='pybb_toggle_hid_topic'),
 
     # Post
     url('^topic/(?P<topic_id>\d+)/post/add/$', views.add_post,

=== modified file 'pybb/views.py'
--- pybb/views.py	2018-10-03 09:01:09 +0000
+++ pybb/views.py	2018-11-17 11:25:00 +0000
@@ -10,7 +10,7 @@
 from django.urls import reverse
 from django.db import connection
 from django.utils import translation
-from django.shortcuts import render
+from django.shortcuts import render, redirect
 
 
 from pybb.util import render_to, paged, build_form, quote_text, ajax, urlize
@@ -29,52 +29,32 @@
 
 
 def index_ctx(request):
-    quick = {'posts': Post.objects.count(),
-             'topics': Topic.objects.count(),
-             'users': User.objects.count(),
-             'last_topics': Topic.objects.all().select_related()[:pybb_settings.QUICK_TOPICS_NUMBER],
-             'last_posts': Post.objects.order_by('-created').select_related()[:pybb_settings.QUICK_POSTS_NUMBER],
-             }
-
     cats = Category.objects.all().select_related()
 
-    return {'cats': cats,
-            'quick': quick,
-            }
+    return {'cats': cats }
 index = render_to('pybb/index.html')(index_ctx)
 
 
 def show_category_ctx(request, category_id):
     category = get_object_or_404(Category, pk=category_id)
-    quick = {'posts': category.posts.count(),
-             'topics': category.topics.count(),
-             'last_topics': category.topics.select_related()[:pybb_settings.QUICK_TOPICS_NUMBER],
-             'last_posts': category.posts.order_by('-created').select_related()
-             [:pybb_settings.QUICK_POSTS_NUMBER],
-             }
-    return {'category': category,
-            'quick': quick,
-            }
+
+    return {'category': category }
 show_category = render_to('pybb/category.html')(show_category_ctx)
 
 
 def show_forum_ctx(request, forum_id):
     forum = get_object_or_404(Forum, pk=forum_id)
 
-    quick = {'posts': forum.post_count,
-             'topics': forum.topics.count(),
-             'last_topics': forum.topics.all().select_related()[:pybb_settings.QUICK_TOPICS_NUMBER],
-             'last_posts': forum.posts.order_by('-created').select_related()
-             [:pybb_settings.QUICK_POSTS_NUMBER],
-             }
+    moderator = (request.user.is_superuser or
+                 request.user in forum.moderators.all())
 
     topics = forum.topics.order_by(
-        '-sticky', '-updated').exclude(posts__hidden=True).select_related()
+        '-sticky', '-updated').select_related()
 
     return {'forum': forum,
             'topics': topics,
-            'quick': quick,
             'page_size': pybb_settings.FORUM_PAGE_SIZE,
+            'moderator': moderator,
             }
 show_forum = render_to('pybb/forum.html')(show_forum_ctx)
 
@@ -106,8 +86,16 @@
     subscribed = (request.user.is_authenticated and
                   request.user in topic.subscribers.all())
 
-    posts = topic.posts.exclude(hidden=True).select_related()
-
+
+    is_spam = False
+    if topic.is_hidden:
+            is_spam = topic.posts.first().is_spam()
+
+    if moderator:
+        posts = topic.posts.select_related()
+    else:
+        posts = topic.posts.exclude(hidden=True).select_related()
+ 
     # TODO: fetch profiles
     # profiles = Profile.objects.filter(user__pk__in=
     #     set(x.user.id for x in page.object_list))
@@ -127,6 +115,7 @@
             'posts': posts,
             'page_size': pybb_settings.TOPIC_PAGE_SIZE,
             'form_url': reverse('pybb_add_post', args=[topic.id]),
+            'is_spam': is_spam,
             }
 show_topic = render_to('pybb/topic.html')(show_topic_ctx)
 
@@ -393,3 +382,15 @@
 
 def pybb_moderate_info(request):
     return render(request, 'pybb/pybb_moderate_info.html')
+
+
+def toggle_hidden_topic(request, topic_id):
+    topic = get_object_or_404(Topic, pk=topic_id)
+    first_post = topic.posts.all()[0]
+    if first_post.hidden:
+        first_post.hidden = False
+    else:
+        first_post.hidden = True
+    first_post.save()
+    
+    return redirect(topic)
\ No newline at end of file

=== modified file 'templates/pybb/forum.html'
--- templates/pybb/forum.html	2018-10-15 16:11:43 +0000
+++ templates/pybb/forum.html	2018-11-17 11:25:00 +0000
@@ -51,6 +51,7 @@
 		<tbody>
 		{% for topic in object_list %}
 		<tr class="{% cycle 'odd' 'even' %}">
+			{% if not topic.is_hidden %}
 			<td class="forumIcon center">
 				{% if topic|pybb_has_unreads:user %}
 				<img src="{{ MEDIA_URL }}forum/img/doc_big_work_star.png" style="margin: 0px;" alt="" class="middle" />
@@ -74,6 +75,9 @@
 				<span class="small">on {{ topic.last_post.created|custom_date:user }}</span>
 				{% endif %}
 			</td>
+			{% elif moderator %}
+				<td colspan="4" class="center errormessage">Hidden Topic: <a href="{{ topic.get_absolute_url }}">{{ topic.name }}</a></td>
+			{% endif %}
 		</tr>
 		{% endfor %}
 		</tbody>

=== modified file 'templates/pybb/inlines/display_category.html'
--- templates/pybb/inlines/display_category.html	2016-10-29 20:47:11 +0000
+++ templates/pybb/inlines/display_category.html	2018-11-17 11:25:00 +0000
@@ -30,13 +30,15 @@
 			Posts: {{ forum.posts.count }}
 		</td>
 		<td class="lastPost">
-		{%if forum.last_post %}
-			<a href="{{forum.last_post.get_absolute_url}}">{{ forum.last_post.topic.name }}</a><br />
-			<span class="small">by {{ forum.last_post.user|user_link }}<br />
-			on {{ forum.last_post.created|custom_date:user}}</span>
+		{% with last_post=forum.last_post %}
+		{% if last_post %}
+			<a href="{{last_post.get_absolute_url}}">{{ last_post.topic.name }}</a><br />
+			<span class="small">by {{ last_post.user|user_link }}<br />
+			on {{ last_post.created|custom_date:user}}</span>
 		{% else %}
 			&nbsp;
 		{% endif %}
+		{% endwith %}
 		</td>
 	</tr>
 	{% endfor %}

=== modified file 'templates/pybb/topic.html'
--- templates/pybb/topic.html	2018-10-14 13:24:15 +0000
+++ templates/pybb/topic.html	2018-11-17 11:25:00 +0000
@@ -24,281 +24,302 @@
 {% block content_main %}
 <div class="blogEntry">
 	<div class="breadCrumb">
-	<a href="{% url 'pybb_index' %}">Forums</a> &#187; 
-	{% pybb_link topic.forum.category %} &#187; 
-	<a href="{{ topic.forum.get_absolute_url }}">{{ topic.forum.name }}</a> &#187;
-	{{ topic }}
-	</div>
-
-	<div class="posRight">
-	{% if moderator %}
-		{% if topic.sticky %}
-		<a class="button" href="{% url 'pybb_unstick_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/unstick.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Unstick Topic" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_stick_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/sticky.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Stick Topic" %}</span>
-		</a>
-		{% endif %}
-		{% if topic.closed %}
-		<a class="button" href="{% url 'pybb_open_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/open.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Open Topic" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_close_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/closed.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Close Topic" %}</span>
-		</a>
-		{% endif %}
-	{% endif %}
-	{% if user.is_authenticated %}
-		{% if subscribed %}
-		<a class="button" href="{% url 'pybb_delete_subscription' topic.id %}?from_topic">
-			<img src="{{ MEDIA_URL }}forum/img/unsubscribe.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Unsubscribe" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_add_subscription' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/subscribe.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Subscribe" %}</span>
-		</a>
-		{% endif %}
-		<a class="button" href="{% url 'pybb_add_post' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/send.png" alt ="" class="middle" />
-			<span class="middle">{% trans "New Reply" %}</span>
-		</a>
-	{% endif %}
-	</div>
-	{% autopaginate posts page_size as object_list %}
-	{% paginate using "pagination/pagination_mod.html" %}
-
-{% if first_post %}
-	{% ifnotequal first_post posts.0 %}
-		{% with first_post as post %}
-	{% trans "First Post" %}:
-	<table class="forum">
-		<tbody>
-		<tr class="odd">
-			<td class="author">
-				{{ post.user|user_link }}<br />
-				{% if post.user.wlprofile_extras.avatar %}
-				<a href="{% url 'profile_view' post.user %}">
-					<img src="{{ post.user.wlprofile.avatar.url }}" alt="Avatar" />
-				</a>
-				{% endif %}
-				<div class="authorStats">
-				<strong>Joined:</strong> {{ post.user.date_joined|custom_date:user|title }}<br />
-				<strong>Posts:</strong> {{ post.user.wlprofile.post_count }}<br />
-				<img src="{{ MEDIA_URL }}img/{{ post.user.wlprofile.user_status.image }}" alt="Ranking" /><br />
-				<strong>{{ post.user.wlprofile.user_status.text }}</strong><br />
-				{% if post.user.wlprofile.location %}
-				<strong>Location:</strong> {{ post.user.wlprofile.location }}<br />
-				{% endif %}
-				</div>
-			</td>
-			<td class="post">
-				<a id="post-{{ post.id }}" href="{{post.get_absolute_url}}" title="{% trans "Permalink" %}" class="posRight small permalink">&nbsp;</a>
-				<span class="small">Posted at: {{ post.created|custom_date:user}}</span>
-				<hr />
-				<div class="post">
-					{{ post.body_html|safe }}
-				</div>
-
-				{% if post.attachment_cache %}
-					{% for attach in post.attachment_cache %}
-						{% trans "Attachment" %}: <a href="{{ attach.get_absolute_url }}">{{ attach.name }}</a> ({{ attach.size_display }})
-					{% endfor %}
-				{% endif %}
-
-				{% if post.updated %}
-					<span class="small">{% trans "Edited" %}: {{ post.updated|custom_date:user|title}}</span>
-				{% endif %}
-				<hr />
-				{% if user.is_authenticated %}
-					{% ifequal user.wlprofile.show_signatures 1 %}
-						{% if post.user.wlprofile.signature %}
-							{{ post.user.wlprofile.signature|urlize|linebreaks }}
-						{% endif %}
-					{% endifequal %}
-				{% else %}
-					{% if post.user.wlprofile.signature %}
-						{{ post.user.wlprofile.signature|urlize|linebreaks }}
-					{% endif %}
-				{% endif %}
-
-				<button onclick="window.location.href='#top';" class="posRight">
-					<img src="{{ MEDIA_URL }}forum/img/top.png" alt ="" class="middle" />
-					<span class="middle">{% trans "Top" %}</span>
-				</button>
-
-				<button onclick="window.location.href='{% url 'pybb_add_post' topic.id %}?quote_id={{ post.id }}';">
-					<img src="{{ MEDIA_URL }}forum/img/quote.png" alt ="" class="middle" />
-					<span class="middle">{% trans "Quote" %}</span>
-				</button>
-				{% if moderator or post|pybb_posted_by:user %}
-					<button onclick="window.location.href='{% url 'pybb_edit_post' post.id %}';">
-						<img src="{{ MEDIA_URL }}forum/img/edit.png" alt ="" class="middle" />
-						<span class="middle">{% trans "Edit" %}</span>
-					</button>
-					{% if moderator or post|pybb_equal_to:last_post %}
-					<button onclick="window.location.href='{% url 'pybb_delete_post' post.id %}';">
-						<img src="{{ MEDIA_URL }}forum/img/delete.png" alt ="" class="middle" />
-						<span class="middle">{% trans "Delete" %}</span>
-					</button>
-					{% endif %}
-				{% endif %}
-			</td>
-		</tr>
-		</tbody>
-	</table>
-	<br /><hr /><br />
-		{% endwith %}
-	{% endifnotequal %}
-{% endif %}
-
-	<table class="forum">
-		<tbody>
-	{% for post in object_list %}
-		{% comment %}
-		TODO (Franku): use
-		{% include 'pybb/inlines/post.html' %}
-		{% endcomment %}
-		<tr class="{% cycle 'odd' 'even' %}">
-			<td class="author">
-				{{ post.user|user_link }}<br />
-				{% if post.user.wlprofile.avatar %}
-				<a href="{% url 'profile_view' post.user %}">
-					<img src="{{ post.user.wlprofile.avatar.url }}" alt="Avatar" />
-				</a>
-				{% endif %}
-				<div class="authorStats">
-				<strong>Joined:</strong> {{ post.user.date_joined|custom_date:user|title }}<br />
-				<strong>Posts:</strong> {{ post.user.wlprofile.post_count }}<br />
-				<img src="{{ MEDIA_URL }}img/{{ post.user.wlprofile.user_status.image }}" alt="Ranking" /><br />
-				<strong>{{ post.user.wlprofile.user_status.text }}</strong><br />
-				{% if post.user.wlprofile.location %}
-				<strong>Location:</strong> {{ post.user.wlprofile.location }}<br />
-				{% endif %}
-				</div>
-			</td>
-			<td class="post">
-				<a id="post-{{ post.id }}" href="{{post.get_absolute_url}}" title="{% trans "Permalink" %}" class="posRight small permalink">&nbsp;</a>
-				<span class="small">Posted at: {{ post.created|custom_date:user}}</span>
-				<hr />
-				<div class="post">
-					{{ post.body_html|safe }}
-				</div>
-
-				{% if post.attachment_cache %}
-					{% for attach in post.attachment_cache %}
-						{% trans "Attachment" %}: <a href="{{ attach.get_absolute_url }}">{{ attach.name }}</a> ({{ attach.size_display }})
-					{% endfor %}
-				{% endif %}
-
-				{% if post.updated %}
-					<span class="small">{% trans "Edited" %}: {{ post.updated|custom_date:user|title}}</span>
-				{% endif %}
-				<hr />
-				{% if user.is_authenticated %}
-					{% ifequal user.wlprofile.show_signatures 1 %}
-						{% if post.user.wlprofile.signature %}
-							{{ post.user.wlprofile.signature|urlize|linebreaks }}
-						{% endif %}
-					{% endifequal %}
-				{% else %}
-					{% if post.user.wlprofile.signature %}
-						{{ post.user.wlprofile.signature|urlize|linebreaks }}
-					{% endif %}
-				{% endif %}
-
-				<a class="button posRight" href="#top">
-					<img src="{{ MEDIA_URL }}forum/img/top.png" alt ="" class="middle" />
-					<span class="middle">{% trans "Top" %}</span>
-				</a>
-
-				<a class="button" href="{% url 'pybb_add_post' topic.id %}?quote_id={{ post.id }}">
-					<img src="{{ MEDIA_URL }}forum/img/quote.png" alt ="" class="middle" />
-					<span class="middle">{% trans "Quote" %}</span>
-				</a>
-				{% if moderator or post|pybb_posted_by:user %}
-					<a class="button" href="{% url 'pybb_edit_post' post.id %}">
-						<img src="{{ MEDIA_URL }}forum/img/edit.png" alt ="" class="middle" />
-						<span class="middle">{% trans "Edit" %}</span>
-					</a>
-					{% if moderator or post|pybb_equal_to:last_post %}
-					<a class="button" href="{% url 'pybb_delete_post' post.id %}">
-						<img src="{{ MEDIA_URL }}forum/img/delete.png" alt ="" class="middle" />
-						<span class="middle">{% trans "Delete" %}</span>
-					</a>
-					{% endif %}
-				{% endif %}
-			</td>
-		</tr>
-		{% if not forloop.last %}
-		{# no spacer at end of table #}
-		<tr class="spacer">
-			<td></td>
-			<td></td>
-		</tr>
-		{% endif %}
-	{% endfor %}
-		</tbody>
-	</table>
-
-	<div class="posRight">
-	{% if moderator %}
-		{% if topic.sticky %}
-		<a class="button" href="{% url 'pybb_unstick_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/unstick.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Unstick Topic" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_stick_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/sticky.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Stick Topic" %}</span>
-		</a>
-		{% endif %}
-		{% if topic.closed %}
-		<a class="button" href="{% url 'pybb_open_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/open.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Open Topic" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_close_topic' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/closed.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Close Topic" %}</span>
-		</a>
-		{% endif %}
-	{% endif %}
-	{% if user.is_authenticated %}
-		{% if subscribed %}
-		<a class="button" href="{% url 'pybb_delete_subscription' topic.id %}?from_topic">
-			<img src="{{ MEDIA_URL }}forum/img/unsubscribe.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Unsubscribe" %}</span>
-		</a>
-		{% else %}
-		<a class="button" href="{% url 'pybb_add_subscription' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/subscribe.png" alt ="" class="middle" />
-			<span class="middle">{% trans "Subscribe" %}</span>
-		</a>
-		{% endif %}
-		<a class="button" href="{% url 'pybb_add_post' topic.id %}">
-			<img src="{{ MEDIA_URL }}forum/img/send.png" alt ="" class="middle" />
-			<span class="middle">{% trans "New Reply" %}</span>
-		</a>
-	{% endif %}
-	</div>
-	{% paginate %}
-</div>
-
-{% if user.is_authenticated %}
-	{% if not topic.closed %}
-		{% include "pybb/inlines/add_post_form.html" %}
-	{% endif %}
-{% endif %}
-
+		<a href="{% url 'pybb_index' %}">Forums</a> &#187; 
+		{% pybb_link topic.forum.category %} &#187; 
+		<a href="{{ topic.forum.get_absolute_url }}">{{ topic.forum.name }}</a> &#187;
+		{{ topic }}
+		</div>
+	{% if topic.is_hidden %}
+		<p>This topic is hidden. Either it waits for a review, or it was hid by a moderator intentionally.</p>
+		{% if posts.0.is_spam and moderator %}
+			<p>This topics first post is possible spam. Toggle visibilty to show the post. If this is spam, consider to delete the user:</p>
+			<p>To delete the user, go to:<a href="/admin/auth/user/{{posts.0.user.pk}}/change/"> Admin user-page for the posts author</a></p>
+		{% endif %}
+		<div class="posRight">
+		{% if moderator %}
+			<a class="button" href="{% url 'pybb_toggle_hid_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/topic_show.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Toggle Visibility" %}</span>
+			</a>
+		{% endif %}
+	{% else %}
+		<div class="posRight">
+		{% if moderator %}
+			<a class="button" href="{% url 'pybb_toggle_hid_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/topic_hide.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Toggle Visibility" %}</span>
+			</a>
+			{% if topic.sticky %}
+			<a class="button" href="{% url 'pybb_unstick_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/unstick.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Unstick Topic" %}</span>
+			</a>
+			{% else %}
+			<a class="button" href="{% url 'pybb_stick_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/sticky.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Stick Topic" %}</span>
+			</a>
+			{% endif %}
+			{% if topic.closed %}
+			<a class="button" href="{% url 'pybb_open_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/open.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Open Topic" %}</span>
+			</a>
+			{% else %}
+			<a class="button" href="{% url 'pybb_close_topic' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/closed.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Close Topic" %}</span>
+			</a>
+			{% endif %}
+		{% endif %}
+		{% if user.is_authenticated %}
+			{% if subscribed %}
+			<a class="button" href="{% url 'pybb_delete_subscription' topic.id %}?from_topic">
+				<img src="{{ MEDIA_URL }}forum/img/unsubscribe.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Unsubscribe" %}</span>
+			</a>
+			{% else %}
+			<a class="button" href="{% url 'pybb_add_subscription' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/subscribe.png" alt ="" class="middle" />
+				<span class="middle">{% trans "Subscribe" %}</span>
+			</a>
+			{% endif %}
+			<a class="button" href="{% url 'pybb_add_post' topic.id %}">
+				<img src="{{ MEDIA_URL }}forum/img/send.png" alt ="" class="middle" />
+				<span class="middle">{% trans "New Reply" %}</span>
+			</a>
+		{% endif %}
+			</div>
+			{% autopaginate posts page_size as object_list %}
+			{% paginate using "pagination/pagination_mod.html" %}
+		
+		{% if first_post %}
+			{% ifnotequal first_post posts.0 %}
+				{% with first_post as post %}
+			{% trans "First Post" %}:
+			<table class="forum">
+				<tbody>
+				<tr class="odd">
+					<td class="author">
+						{{ post.user|user_link }}<br />
+						{% if post.user.wlprofile_extras.avatar %}
+						<a href="{% url 'profile_view' post.user %}">
+							<img src="{{ post.user.wlprofile.avatar.url }}" alt="Avatar" />
+						</a>
+						{% endif %}
+						<div class="authorStats">
+						<strong>Joined:</strong> {{ post.user.date_joined|custom_date:user|title }}<br />
+						<strong>Posts:</strong> {{ post.user.wlprofile.post_count }}<br />
+						<img src="{{ MEDIA_URL }}img/{{ post.user.wlprofile.user_status.image }}" alt="Ranking" /><br />
+						<strong>{{ post.user.wlprofile.user_status.text }}</strong><br />
+						{% if post.user.wlprofile.location %}
+						<strong>Location:</strong> {{ post.user.wlprofile.location }}<br />
+						{% endif %}
+						</div>
+					</td>
+					<td class="post">
+						<a id="post-{{ post.id }}" href="{{post.get_absolute_url}}" title="{% trans "Permalink" %}" class="posRight small permalink">&nbsp;</a>
+						<span class="small">Posted at: {{ post.created|custom_date:user}}</span>
+						<hr />
+						<div class="post">
+							{{ post.body_html|safe }}
+						</div>
+
+						{% if post.attachment_cache %}
+							{% for attach in post.attachment_cache %}
+								{% trans "Attachment" %}: <a href="{{ attach.get_absolute_url }}">{{ attach.name }}</a> ({{ attach.size_display }})
+							{% endfor %}
+						{% endif %}
+
+						{% if post.updated %}
+							<span class="small">{% trans "Edited" %}: {{ post.updated|custom_date:user|title}}</span>
+						{% endif %}
+						<hr />
+						{% if user.is_authenticated %}
+							{% ifequal user.wlprofile.show_signatures 1 %}
+								{% if post.user.wlprofile.signature %}
+									{{ post.user.wlprofile.signature|urlize|linebreaks }}
+								{% endif %}
+							{% endifequal %}
+						{% else %}
+							{% if post.user.wlprofile.signature %}
+								{{ post.user.wlprofile.signature|urlize|linebreaks }}
+							{% endif %}
+						{% endif %}
+
+						<button onclick="window.location.href='#top';" class="posRight">
+							<img src="{{ MEDIA_URL }}forum/img/top.png" alt ="" class="middle" />
+							<span class="middle">{% trans "Top" %}</span>
+						</button>
+
+						<button onclick="window.location.href='{% url 'pybb_add_post' topic.id %}?quote_id={{ post.id }}';">
+							<img src="{{ MEDIA_URL }}forum/img/quote.png" alt ="" class="middle" />
+							<span class="middle">{% trans "Quote" %}</span>
+						</button>
+						{% if moderator or post|pybb_posted_by:user %}
+							<button onclick="window.location.href='{% url 'pybb_edit_post' post.id %}';">
+								<img src="{{ MEDIA_URL }}forum/img/edit.png" alt ="" class="middle" />
+								<span class="middle">{% trans "Edit" %}</span>
+							</button>
+							{% if moderator or post|pybb_equal_to:last_post %}
+							<button onclick="window.location.href='{% url 'pybb_delete_post' post.id %}';">
+								<img src="{{ MEDIA_URL }}forum/img/delete.png" alt ="" class="middle" />
+								<span class="middle">{% trans "Delete" %}</span>
+							</button>
+							{% endif %}
+						{% endif %}
+					</td>
+				</tr>
+				</tbody>
+			</table>
+			<br /><hr /><br />
+				{% endwith %}
+			{% endifnotequal %}
+		{% endif %}
+		
+			<table class="forum">
+				<tbody>
+			{% for post in object_list %}
+				{% comment %}
+				TODO (Franku): use
+				{% include 'pybb/inlines/post.html' %}
+				{% endcomment %}
+				<tr class="{% cycle 'odd' 'even' %}" {% if post.is_spam %} style="background-color: gray" {% endif %}>
+					<td class="author">
+						{{ post.user|user_link }}<br />
+						{% if post.user.wlprofile.avatar %}
+						<a href="{% url 'profile_view' post.user %}">
+							<img src="{{ post.user.wlprofile.avatar.url }}" alt="Avatar" />
+						</a>
+						{% endif %}
+						<div class="authorStats">
+						<strong>Joined:</strong> {{ post.user.date_joined|custom_date:user|title }}<br />
+						<strong>Posts:</strong> {{ post.user.wlprofile.post_count }}<br />
+						<img src="{{ MEDIA_URL }}img/{{ post.user.wlprofile.user_status.image }}" alt="Ranking" /><br />
+						<strong>{{ post.user.wlprofile.user_status.text }}</strong><br />
+						{% if post.user.wlprofile.location %}
+						<strong>Location:</strong> {{ post.user.wlprofile.location }}<br />
+						{% endif %}
+						</div>
+					</td>
+					<td class="post">
+						<a id="post-{{ post.id }}" href="{{post.get_absolute_url}}" title="{% trans "Permalink" %}" class="posRight small permalink">&nbsp;</a>
+						<span class="small">Posted at: {{ post.created|custom_date:user}}</span>
+						<hr />
+						<div class="post">
+							{{ post.body_html|safe }}
+						</div>
+
+						{% if post.attachment_cache %}
+							{% for attach in post.attachment_cache %}
+								{% trans "Attachment" %}: <a href="{{ attach.get_absolute_url }}">{{ attach.name }}</a> ({{ attach.size_display }})
+							{% endfor %}
+						{% endif %}
+
+						{% if post.updated %}
+							<span class="small">{% trans "Edited" %}: {{ post.updated|custom_date:user|title}}</span>
+						{% endif %}
+						<hr />
+						{% if user.is_authenticated %}
+							{% ifequal user.wlprofile.show_signatures 1 %}
+								{% if post.user.wlprofile.signature %}
+									{{ post.user.wlprofile.signature|urlize|linebreaks }}
+								{% endif %}
+							{% endifequal %}
+						{% else %}
+							{% if post.user.wlprofile.signature %}
+								{{ post.user.wlprofile.signature|urlize|linebreaks }}
+							{% endif %}
+						{% endif %}
+
+						<a class="button posRight" href="#top">
+							<img src="{{ MEDIA_URL }}forum/img/top.png" alt ="" class="middle" />
+							<span class="middle">{% trans "Top" %}</span>
+						</a>
+
+						<a class="button" href="{% url 'pybb_add_post' topic.id %}?quote_id={{ post.id }}">
+							<img src="{{ MEDIA_URL }}forum/img/quote.png" alt ="" class="middle" />
+							<span class="middle">{% trans "Quote" %}</span>
+						</a>
+						{% if moderator or post|pybb_posted_by:user %}
+							<a class="button" href="{% url 'pybb_edit_post' post.id %}">
+								<img src="{{ MEDIA_URL }}forum/img/edit.png" alt ="" class="middle" />
+								<span class="middle">{% trans "Edit" %}</span>
+							</a>
+							{% if moderator or post|pybb_equal_to:last_post %}
+							<a class="button" href="{% url 'pybb_delete_post' post.id %}">
+								<img src="{{ MEDIA_URL }}forum/img/delete.png" alt ="" class="middle" />
+								<span class="middle">{% trans "Delete" %}</span>
+							</a>
+							{% endif %}
+						{% endif %}
+					</td>
+				</tr>
+				{% if not forloop.last %}
+				{# no spacer at end of table #}
+				<tr class="spacer">
+					<td></td>
+					<td></td>
+				</tr>
+				{% endif %}
+			{% endfor %}
+				</tbody>
+			</table>
+
+			<div class="posRight">
+			{% if moderator %}
+			<a class="button" href="{% url 'pybb_toggle_hid_topic' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/topic_hide.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Toggle Visibility" %}</span>
+				</a>
+				{% if topic.sticky %}
+				<a class="button" href="{% url 'pybb_unstick_topic' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/unstick.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Unstick Topic" %}</span>
+				</a>
+				{% else %}
+				<a class="button" href="{% url 'pybb_stick_topic' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/sticky.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Stick Topic" %}</span>
+				</a>
+				{% endif %}
+				{% if topic.closed %}
+				<a class="button" href="{% url 'pybb_open_topic' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/open.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Open Topic" %}</span>
+				</a>
+				{% else %}
+				<a class="button" href="{% url 'pybb_close_topic' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/closed.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Close Topic" %}</span>
+				</a>
+				{% endif %}
+			{% endif %}
+			{% if user.is_authenticated %}
+				{% if subscribed %}
+				<a class="button" href="{% url 'pybb_delete_subscription' topic.id %}?from_topic">
+					<img src="{{ MEDIA_URL }}forum/img/unsubscribe.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Unsubscribe" %}</span>
+				</a>
+				{% else %}
+				<a class="button" href="{% url 'pybb_add_subscription' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/subscribe.png" alt ="" class="middle" />
+					<span class="middle">{% trans "Subscribe" %}</span>
+				</a>
+				{% endif %}
+				<a class="button" href="{% url 'pybb_add_post' topic.id %}">
+					<img src="{{ MEDIA_URL }}forum/img/send.png" alt ="" class="middle" />
+					<span class="middle">{% trans "New Reply" %}</span>
+				</a>
+			{% endif %}
+			</div>
+			{% paginate %}
+		</div>
+
+		{% if user.is_authenticated %}
+			{% if not topic.closed %}
+				{% include "pybb/inlines/add_post_form.html" %}
+			{% endif %}
+		{% endif %}
+	{% endif %}
 {% endblock %}


Follow ups