# HG changeset patch
# User neko259 <neko259@gmail.com>
# Date 2013-05-23 19:29:27
# Node ID 384df4e145fe8579af36f1f2edb1b904d537ea8a
# Parent  97bf814ea09c3a770751f879dbc0e2c40f70005e

Compiling regexes for gets. #17 Added pagination. #28 Visually differing the dead (not bumpable) threads.

diff --git a/boards/models.py b/boards/models.py
--- a/boards/models.py
+++ b/boards/models.py
@@ -3,6 +3,7 @@ import re
 from django.db import models
 from django.utils import timezone
 import time
+import math
 
 from neboard import settings
 from markupfield.fields import MarkupField
@@ -23,6 +24,8 @@ def update_image_filename(instance, file
 
 
 class PostManager(models.Manager):
+    ALL_PAGES = -1
+
     def create_post(self, title, text, image=None, parent_id=NO_PARENT,
                     ip=NO_IP, tags=None):
         post = self.create(title=title,
@@ -56,13 +59,22 @@ class PostManager(models.Manager):
         for post in posts:
             self.delete_post(post)
 
-    def get_threads(self, tag=None):
+    def get_threads(self, tag=None, page=ALL_PAGES):
         if tag:
             threads = self.filter(parent=NO_PARENT, tags=tag)
         else:
             threads = self.filter(parent=NO_PARENT)
         threads = list(threads.order_by('-last_edit_time'))
 
+        if page != self.ALL_PAGES:
+            thread_count = len(threads)
+
+            if page < self.get_thread_page_count(tag=tag):
+                start_thread = page * settings.THREADS_PER_PAGE
+                end_thread = min(start_thread + settings.THREADS_PER_PAGE,
+                                 thread_count)
+                threads = threads[start_thread:end_thread]
+
         return threads
 
     def get_thread(self, opening_post_id):
@@ -81,6 +93,15 @@ class PostManager(models.Manager):
 
         return len(posts) > 0
 
+    def get_thread_page_count(self, tag=None):
+        if tag:
+            threads = self.filter(parent=NO_PARENT, tags=tag)
+        else:
+            threads = self.filter(parent=NO_PARENT)
+
+        return int(math.ceil(len(threads) / float(settings.THREADS_PER_PAGE)))
+
+
     def _delete_old_threads(self):
         """
         Preserves maximum thread count. If there are too many threads,
@@ -106,8 +127,7 @@ class PostManager(models.Manager):
     def _bump_thread(self, thread_id):
         thread = self.get(id=thread_id)
 
-        replies_count = len(self.get_thread(thread_id))
-        if replies_count <= settings.MAX_POSTS_PER_THREAD:
+        if thread.can_bump():
             thread.last_edit_time = timezone.now()
             thread.save()
 
@@ -162,6 +182,9 @@ class Post(models.Model):
     tags = models.ManyToManyField(Tag)
     last_edit_time = models.DateTimeField()
 
+    regex_pretty = re.compile(r'^\d(0)+$')
+    regex_same = re.compile(r'^(.)\1+$')
+
     def __unicode__(self):
         return self.title + ' (' + self.text.raw + ')'
 
@@ -192,12 +215,18 @@ class Post(models.Model):
 
         first = self.id == 1
 
-        # TODO Compile regexes
+        id_str = str(self.id)
+        pretty = self.regex_pretty.match(id_str)
+        same_digits = self.regex_same.match(id_str)
+
+        return first or pretty or same_digits
 
-        id_str = str(self.id)
-        pretty = re.match(r'^\d(0)+$', id_str)
-        same_digits = re.match(r'^(.)\1+$', id_str)
-        return first or pretty or same_digits
+    def can_bump(self):
+        """Check if the thread can be bumped by replying"""
+
+        replies_count = len(Post.objects.get_thread(self.id))
+
+        return replies_count <= settings.MAX_POSTS_PER_THREAD
 
 
 class Admin(models.Model):
diff --git a/boards/static/css/md/base_page.css b/boards/static/css/md/base_page.css
--- a/boards/static/css/md/base_page.css
+++ b/boards/static/css/md/base_page.css
@@ -42,7 +42,7 @@ html {
     color: #fff380;
 }
 
-.post {
+.post, .dead_post{
     background: #333;
     margin: 5px;
     padding: 10px;
@@ -169,4 +169,8 @@ blockquote {
 
 * {
     text-decoration: none;
+}
+
+.dead_post {
+    background-color: #442222;
 }
\ No newline at end of file
diff --git a/boards/tests.py b/boards/tests.py
--- a/boards/tests.py
+++ b/boards/tests.py
@@ -107,4 +107,27 @@ class BoardTests(TestCase):
             self._create_post()
 
         self.assertEqual(settings.MAX_THREAD_COUNT,
-                         len(Post.objects.get_threads()))
\ No newline at end of file
+                         len(Post.objects.get_threads()))
+
+    def test_get(self):
+        """Test if the get computes properly"""
+
+        post = self._create_post()
+
+        self.assertTrue(post.is_get())
+
+    def test_pages(self):
+        """Test that the thread list is properly split into pages"""
+
+        PAGE_NUMBER = 2
+
+        for i in range(settings.MAX_THREAD_COUNT):
+            self._create_post()
+
+        all_threads = Post.objects.get_threads()
+
+        posts_in_second_page = Post.objects.get_threads(page=1)
+        first_post = posts_in_second_page[0]
+
+        self.assertEqual(all_threads[settings.THREADS_PER_PAGE].id,
+                                     first_post.id)
\ No newline at end of file
diff --git a/boards/urls.py b/boards/urls.py
--- a/boards/urls.py
+++ b/boards/urls.py
@@ -4,16 +4,20 @@ from boards import views
 urlpatterns = patterns('',
 
     # /boards/
-    url(r'^$', views.index, name = 'index'),
+    url(r'^$', views.index, name='index'),
+    # /boards/page/
+    url(r'^page/(?P<page>\w+)/$', views.index, name='index'),
 
     # login page
     url(r'^login$', views.login, name='login'),
     # logout page
     url(r'^logout$', views.logout, name='logout'),
 
-    # /boards/tag/
+    # /boards/tag/tag_name/
     url(r'^tag/(?P<tag_name>\w+)/$', views.tag, name='tag'),
-    # /boards/post_id/
+    # /boards/tag/tag_id/page/
+    url(r'^tag/(?P<tag_name>\w+)/page/(?P<page>\w+)/$', views.tag, name='tag'),
+    # /boards/thread/
     url(r'^thread/(?P<post_id>\w+)/$', views.thread, name='thread'),
     # /boards/theme/theme_name/
     url(r'^settings$', views.settings, name='settings'),
diff --git a/boards/views.py b/boards/views.py
--- a/boards/views.py
+++ b/boards/views.py
@@ -9,18 +9,20 @@ from django.http import HttpResponseRedi
 import neboard
 
 
-def index(request):
+def index(request, page=0):
     context = RequestContext(request)
 
     if request.method == 'POST':
         return new_post(request)
     else:
-        threads = Post.objects.get_threads()
+        threads = Post.objects.get_threads(page=int(page))
 
+        # TODO Get rid of the duplicate code in index and tag views
         context['threads'] = None if len(threads) == 0 else threads
         context['form'] = forms.ThreadForm()
         context['tags'] = Tag.objects.get_not_empty_tags()
         context['theme'] = _get_theme(request)
+        context['pages'] = range(Post.objects.get_thread_page_count())
 
         return render(request, 'posting_general.html',
                       context)
@@ -80,11 +82,11 @@ def new_post(request, thread_id=boards.m
                         + str(post.id))
 
 
-def tag(request, tag_name):
+def tag(request, tag_name, page=0):
     """Get all tag threads (posts without a parent)."""
 
     tag = Tag.objects.get(name=tag_name)
-    threads = Post.objects.get_threads(tag=tag)
+    threads = Post.objects.get_threads(tag=tag, page=int(page))
 
     if request.method == 'POST':
         return new_post(request)
@@ -94,6 +96,7 @@ def tag(request, tag_name):
         context['tag'] = tag_name
         context['tags'] = Tag.objects.get_not_empty_tags()
         context['theme'] = _get_theme(request)
+        context['pages'] = range(Post.objects.get_thread_page_count(tag=tag))
 
         context['form'] = forms.ThreadForm(initial={'tags': tag_name})
 
diff --git a/neboard/settings.py b/neboard/settings.py
--- a/neboard/settings.py
+++ b/neboard/settings.py
@@ -168,8 +168,9 @@ LOGGING = {
 }
 
 # Custom imageboard settings
-MAX_POSTS_PER_THREAD = 500 # Thread bumplimit
+MAX_POSTS_PER_THREAD = 10 # Thread bumplimit
 MAX_THREAD_COUNT = 20 # Old threads will be deleted to preserve this count
+THREADS_PER_PAGE = 2
 SITE_NAME = 'Neboard'
 
 THEMES = [
diff --git a/templates/posting_general.html b/templates/posting_general.html
--- a/templates/posting_general.html
+++ b/templates/posting_general.html
@@ -11,7 +11,11 @@
 
 	{% if threads %}
 		{% for thread in threads %}
-            <div class="post">
+            {% if thread.can_bump %}
+                <div class="post">
+            {% else %}
+                <div class="dead_post">
+            {% endif %}
             {% if thread.image %}
                 <div class="image">
                     <a href="{{ thread.image.url }}"><img
@@ -87,7 +91,17 @@
 {% block metapanel %}
 
     <span class="metapanel">
-        Neboard 2013-05 (dev)
+        <b>Neboard 2013-05 (dev)</b>
+        {% trans "Pages:" %}
+        {% for page in pages %}
+            [<a href="
+            {% if tag %}
+                {% url "tag" tag_name=tag page=page %}
+            {% else %}
+                {% url "index" page=page %}
+            {% endif %}
+            ">{{ page }}</a>]
+        {% endfor %}
     </span>
 
 {% endblock %}
\ No newline at end of file