Browse Source

WIP thread view

Rafał Pitoń 10 years ago
parent
commit
4ee49ceb88

+ 15 - 2
misago/static/misago/css/misago/header.less

@@ -167,15 +167,28 @@
       display: block;
       clear: both;
       margin-bottom: 0;
+      position: relative;
+      top: @line-height-computed * 0.6;
 
       color: @text-muted;
 
+      img {
+      	border-radius: @border-radius-small;
+      	position: relative;
+      	bottom: 1px;
+      }
+
       a:link, a:visited {
         color: @text-muted;
       }
 
-      a:active, a:hover {
-        color: @text-color;
+      a:hover {
+        color: @state-hover;
+        text-decoration: none;
+      }
+
+      a:active {
+        color: @state-clicked;
         text-decoration: none;
       }
     }

+ 1 - 1
misago/templates/misago/threads/list.html

@@ -89,7 +89,7 @@
               {% endif %}
             {% endif %}
 
-            <a href="#" class="item-title">
+            <a href="{{ thread.get_absolute_url }}" class="item-title">
               {{ thread.title }}
             </a>
 

+ 65 - 0
misago/templates/misago/threads/thread.html

@@ -0,0 +1,65 @@
+{% extends "misago/base.html" %}
+{% load humanize i18n misago_avatars misago_stringutils %}
+
+
+{% block title %}{{ thread.title }} | {{ block.super }}{% endblock title %}
+
+
+{% block meta-description %}{% if thread.first_post.is_valid %}{{ thread.first_post.short|striplinebreaks }} {% endif %}{% blocktrans trimmed with replies=thread.replies started=thread.started_on|date last_post=thread.last_post_on|date count counter=thread.replies %}
+{{ replies }} reply since {{ started }}. Last post on {{ last_post }}.
+{% plural %}
+{{ replies }} replies since {{ started }}. Last post on {{ last_post }}.
+{% endblocktrans %}{% endblock meta-description %}
+
+
+{% block content %}
+<div{% if forum.css %} class="page-{{ forum.css_class }}"{% endif %}>
+  <div class="page-header">
+    <div class="container">
+
+      {% if path %}
+      <ol class="breadcrumb">
+        {% for crumb in path %}
+        <li>
+          <a href="{{ crumb.get_absolute_url }}">{{ crumb.name }}</a>{% if not forloop.last %}<span class="fa fa-chevron-right"></span>{% endif %}
+        </li>
+        {% endfor %}
+      </ol>
+      {% endif %}
+
+      <h1>{{ thread.title }}</h1>
+
+      <ul class="list-inline page-details">
+        <li class="tooltip-bottom" title="{% trans "Thread autor" %}">
+          {% if thread.starter_id %}
+            <a href="{% url USER_PROFILE_URL user_slug=thread.starter_slug user_id=thread.starter_id %}">
+              <img src="{{ thread.starter_id|avatar:20 }}" alt="{% trans "Avatar" %}"> {{ thread.starter_name }}
+            </a>
+          {% else %}
+            <span class="fa fa-user"></span> {{ thread.starter_name }}
+          {% endif %}
+        <li>
+        <li>
+          <span class="fa fa-comment"></span> {% blocktrans trimmed with replies=thread.replies|intcomma count counter=thread.replies %}
+            {{ replies }} reply
+          {% plural %}
+            {{ replies }} replies
+          {% endblocktrans %}
+        <li>
+        <li class="tooltip-bottom" title="{% blocktrans with last_post=thread.last_post_on %}Last post from {{ last_post }}{% endblocktrans %}">
+          <span class="fa fa-clock-o"></span>
+          <abbr class="dynamic time-ago" data-timestamp="{{ forum.last_post_on|date:"c" }}">
+            {{ thread.last_post_on|date }}
+          </abbr>
+        </li>
+      </ul>
+
+    </div>
+  </div>
+  <div class="container">
+
+    Blah blah blah!
+
+  </div>
+</div>
+{% endblock %}

+ 6 - 1
misago/threads/checksums.py

@@ -6,6 +6,11 @@ def is_post_valid(post):
     return post.checksum == valid_checksum
 
 
-def update_post_checksum(post):
+def make_post_checksum(post):
     post_seeds = [unicode(v) for v in (post.id, post.poster_ip)]
     return checksums.make_checksum(post.parsed, post_seeds)
+
+
+def update_post_checksum(post):
+    post.checksum = make_post_checksum(post)
+    return post.checksum

+ 10 - 0
misago/threads/models/post.py

@@ -33,5 +33,15 @@ class Post(models.Model):
     is_protected = models.BooleanField(default=False)
 
     @property
+    def short(self):
+        if self.is_valid:
+            if len(self.original) > 150:
+                return '%s...' % self.original[:150].strip()
+            else:
+                return self.original
+        else:
+            return ''
+
+    @property
     def is_valid(self):
         return is_post_valid(self)

+ 23 - 3
misago/threads/models/thread.py

@@ -1,3 +1,4 @@
+from django.core.urlresolvers import reverse
 from django.db import models
 
 from misago.conf import settings
@@ -46,20 +47,39 @@ class Thread(models.Model):
     is_hidden = models.BooleanField(default=False)
     is_closed = models.BooleanField(default=False)
 
+    @property
     def is_announcement(self):
         return self.weight == ANNOUNCEMENT
 
+    @property
     def is_pinned(self):
         return self.weight == PINNED
 
+    @property
+    def link_prefix(self):
+        if self.forum.special_role == 'private_threads':
+            return 'private_thread'
+        else:
+            return 'thread'
+
+    def get_url(self, suffix=None):
+        link = 'misago:%s' % self.link_prefix
+        if suffix:
+            link = '%s_%s' % (link, suffix)
+
+        return reverse(link, kwargs={
+            'thread_slug': self.slug,
+            'thread_id': self.id
+        })
+
     def get_absolute_url(self):
-        pass
+        return self.get_url()
 
     def get_new_reply_url(self):
-        pass
+        return self.get_url('new')
 
     def get_last_reply_url(self):
-        pass
+        return self.get_url('last')
 
     def set_title(self, title):
         self.title = title

+ 5 - 1
misago/threads/permissions.py

@@ -135,7 +135,11 @@ def add_acl_to_post(user, post):
 ACL tests
 """
 def allow_see_thread(user, target):
-    raise NotImplementedError()
+    forum_acl = user.acl['forums'].get(target.forum_id, {})
+    if not forum_acl.get('can_see_all_threads'):
+        if user.is_anonymous() or user.pk != target.starter_id:
+            message = _("You can't see other users threads in this forum.")
+            raise PermissionDenied(user)
 can_see_thread = return_boolean(allow_see_thread)
 
 

+ 31 - 6
misago/threads/views/generic.py

@@ -58,10 +58,12 @@ class ThreadMixin(object):
 
         return thread
 
-    def fetch_thread(self, request, lock=False, **kwargs):
+    def fetch_thread(self, request, lock=False, select_related=None, **kwargs):
         queryset = Thread.objects
         if lock:
             queryset = queryset.select_for_update()
+        if select_related:
+            queryset = queryset.select_related(*select_related)
 
         return get_object_or_404(queryset, id=kwargs.get('thread_id'))
 
@@ -70,7 +72,11 @@ class ThreadMixin(object):
         allow_see_thread(request.user, thread)
 
 
-class ViewBase(ForumMixin, View):
+class PostMixin(object):
+    pass
+
+
+class ViewBase(ForumMixin, ThreadMixin, PostMixin, View):
     templates_dir = ''
     template = ''
 
@@ -109,6 +115,9 @@ class ForumView(ViewBase):
         for thread in page.object_list:
             threads.append(thread)
 
+        for thread in threads:
+            thread.forum = forum
+
         return page, threads
 
     def get_threads_queryset(self, request, forum):
@@ -141,12 +150,28 @@ class ThreadView(ViewBase):
     """
     Basic view for threads
     """
-    def fetch_thread(self, request, **kwargs):
-        pass
+    template = 'thread.html'
 
     def dispatch(self, request, *args, **kwargs):
-        thread = self.fetch_thread(request, **kwargs)
+        if request.method == 'POST':
+            with atomic():
+                return self.real_dispatch(request, *args, **kwargs)
+        else:
+            return self.real_dispatch(request, *args, **kwargs)
 
+    def real_dispatch(self, request, *args, **kwargs):
+        relations = ['forum', 'starter', 'last_poster', 'first_post']
+        thread = self.fetch_thread(request, select_related=relations, **kwargs)
+        forum = thread.forum
+
+        self.check_forum_permissions(request, forum)
+        self.check_thread_permissions(request, thread)
+
+        return self.render(request, {
+            'forum': forum,
+            'path': get_forum_path(forum),
+            'thread': thread
+        })
 
 class PostView(ViewBase):
     """
@@ -229,7 +254,7 @@ class EditorView(ViewBase):
             if 'submit' in request.POST and formset.is_valid():
                 try:
                     formset.save()
-                    return redirect(forum.get_absolute_url())
+                    return redirect(thread.get_absolute_url())
                 except InterruptChanges as e:
                     messages.error(request, e.message)
             else: