changeset 115:0ce0104c7df3

Forums: split topic.
author Brian Neal <bgneal@gmail.com>
date Thu, 22 Oct 2009 02:57:18 +0000
parents 535d02d1c017
children 19b64e8f02a2
files gpp/forums/forms.py gpp/forums/models.py gpp/forums/urls.py gpp/forums/views.py gpp/templates/forums/display_post.html gpp/templates/forums/last_post_info.html gpp/templates/forums/topic.html media/css/base.css media/icons/arrow_branch.png
diffstat 9 files changed, 126 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/forums/forms.py	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/forums/forms.py	Thu Oct 22 02:57:18 2009 +0000
@@ -125,3 +125,30 @@
             self.fields['forums'].label = ''
         self.fields['forums'].required = required
 
+
+class SplitTopicForm(forms.Form):
+    """
+    Form for a moderator to split posts from a topic to a new topic.
+    """
+    name = forms.CharField(label='New topic title', max_length=255,
+            widget=forms.TextInput(attrs={'size': 64}))
+    forums = forms.ModelChoiceField(label='Forum for new topic', 
+          queryset=Forum.objects.none())
+    post_ids = []
+    split_at = False
+
+    def __init__(self, user, *args, **kwargs):
+        super(SplitTopicForm, self).__init__(*args, **kwargs)
+        self.fields['forums'].queryset = \
+            Forum.objects.forums_for_user(user).order_by('name')
+
+    def clean(self):
+        self.post_ids = self.data.getlist('post_ids')
+        if len(self.post_ids) == 0:
+            raise forms.ValidationError('Please select some posts')
+
+        self.split_at = 'split-at' in self.data
+        if self.split_at and len(self.post_ids) > 1:
+            raise forms.ValidationError('Please select only one post to split the topic at')
+
+        return self.cleaned_data
--- a/gpp/forums/models.py	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/forums/models.py	Thu Oct 22 02:57:18 2009 +0000
@@ -228,7 +228,7 @@
     topic = models.ForeignKey(Topic, related_name='posts')
     user = models.ForeignKey(User, related_name='posts')
     creation_date = models.DateTimeField(auto_now_add=True)
-    update_date = models.DateTimeField(auto_now=True)
+    update_date = models.DateTimeField(null=True)
     body = models.TextField()
     html = models.TextField()
     user_ip = models.IPAddressField(blank=True, default='', null=True)
@@ -262,7 +262,11 @@
             self.topic.delete()
 
     def has_been_edited(self):
-        return (self.update_date - self.creation_date) > POST_EDIT_DELTA
+        return self.update_date is not None
+
+    def touch(self):
+        """Call this function to indicate the post has been edited."""
+        self.update_date = datetime.datetime.now()
 
 
 class FlaggedPost(models.Model):
@@ -327,7 +331,7 @@
                 self.last_visit.strftime('%Y-%m-%d %H:%M:%S'))
 
     def save(self, *args, **kwargs):
-        if self.id is None:
+        if self.id is one:
             self.touch()
         super(TopicLastVisit, self).save(*args, **kwargs)
         
--- a/gpp/forums/urls.py	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/forums/urls.py	Thu Oct 22 02:57:18 2009 +0000
@@ -17,6 +17,7 @@
     url(r'^mod/topic/delete/(\d+)/$', 'mod_topic_delete', name='forums-mod_topic_delete'),
     url(r'^mod/topic/lock/(\d+)/$', 'mod_topic_lock', name='forums-mod_topic_lock'),
     url(r'^mod/topic/move/(\d+)/$', 'mod_topic_move', name='forums-mod_topic_move'),
+    url(r'^mod/topic/split/(\d+)/$', 'mod_topic_split', name='forums-mod_topic_split'),
     url(r'^mod/topic/stick/(\d+)/$', 'mod_topic_stick', name='forums-mod_topic_stick'),
     url(r'^post/(\d+)/$', 'goto_post', name='forums-goto_post'),
     url(r'^post/new/(?P<topic_id>\d+)/$', 'new_post', name='forums-new_post'),
--- a/gpp/forums/views.py	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/forums/views.py	Thu Oct 22 02:57:18 2009 +0000
@@ -22,7 +22,8 @@
 from core.functions import email_admins
 from forums.models import Forum, Topic, Post, FlaggedPost, TopicLastVisit, \
         ForumLastVisit
-from forums.forms import NewTopicForm, NewPostForm, PostForm, MoveTopicForm
+from forums.forms import NewTopicForm, NewPostForm, PostForm, MoveTopicForm, \
+        SplitTopicForm
 from forums.unread import get_forum_unread_status, get_topic_unread_status, \
         get_post_unread_status
 
@@ -271,7 +272,9 @@
     if request.method == "POST":
         form = PostForm(request.POST, instance=post)
         if form.is_valid():
-            form.save()
+            post = form.save(commit=False)
+            post.touch()
+            post.save()
             return HttpResponseRedirect(post.get_absolute_url())
     else:
         form = PostForm(instance=post)
@@ -544,6 +547,42 @@
     return HttpResponseRedirect(forum.get_absolute_url())
 
 
+@login_required
+def mod_topic_split(request, id):
+    """
+    This view function allows moderators to split posts off to a new topic.
+    """
+    topic = get_object_or_404(Topic.objects.select_related(), pk=id)
+    if not _can_moderate(topic.forum, request.user):
+        return HttpResponseRedirect(topic.get_absolute_url())
+
+    if request.method == "POST":
+        form = SplitTopicForm(request.user, request.POST)
+        if form.is_valid():
+            if form.split_at:
+                _split_topic_at(topic, form.post_ids[0],
+                        form.cleaned_data['forums'],
+                        form.cleaned_data['name'])
+            else:
+                _split_topic(topic, form.post_ids,
+                        form.cleaned_data['forums'],
+                        form.cleaned_data['name'])
+
+            return HttpResponseRedirect(topic.get_absolute_url())
+    else:
+        form = SplitTopicForm(request.user)
+
+    posts = topic.posts.select_related()
+
+    return render_to_response('forums/mod_split_topic.html', {
+        'forum': topic.forum,
+        'topic': topic,
+        'posts': posts,
+        'form': form,
+        },
+        context_instance=RequestContext(request))
+
+
 def _can_moderate(forum, user):
     """
     Determines if a user has permission to moderate a given forum.
@@ -659,3 +698,39 @@
         tlv.touch()
         tlv.save()
 
+
+def _split_topic_at(topic, post_id, new_forum, new_name):
+    """
+    This function splits the post given by post_id and all posts that come
+    after it in the given topic to a new topic in a new forum.
+    It is assumed the caller has been checked for moderator rights.
+    """
+    post = get_object_or_404(Post, id=post_id)
+    if post.topic == topic:
+        post_ids = Post.objects.filter(topic=topic,
+                creation_date__gte=post.creation_date).values_list('id', flat=True)
+        _split_topic(topic, post_ids, new_forum, new_name)
+
+
+def _split_topic(topic, post_ids, new_forum, new_name):
+    """
+    This function splits the posts given by the post_ids list in the
+    given topic to a new topic in a new forum.
+    It is assumed the caller has been checked for moderator rights.
+    """
+    posts = Post.objects.filter(topic=topic, id__in=post_ids)
+    if len(posts) > 0:
+        new_topic = Topic(forum=new_forum, name=new_name, user=posts[0].user)
+        new_topic.save()
+        for post in posts:
+            post.topic = new_topic
+            post.save()
+        
+        topic.post_count_update()
+        topic.save()
+        new_topic.post_count_update()
+        new_topic.save()
+        topic.forum.sync()
+        topic.forum.save()
+        new_forum.sync()
+        new_forum.save()
--- a/gpp/templates/forums/display_post.html	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/templates/forums/display_post.html	Thu Oct 22 02:57:18 2009 +0000
@@ -19,7 +19,6 @@
       <div class="forum-post-body">
          {{ post.html|safe }}
          {% if post.has_been_edited %}
-         <p>{{ post.creation_date|date:"M d, Y H:i:s" }} {{ post.update_date|date:"M d, Y H:i:s" }}</p>
          <p class="small quiet">Last edited: {{ post.update_date|date:"M d, Y H:i:s" }}</p>
          {% endif %}
       </div>
--- a/gpp/templates/forums/last_post_info.html	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/templates/forums/last_post_info.html	Thu Oct 22 02:57:18 2009 +0000
@@ -1,6 +1,6 @@
 {% if post %}
 <a href="{{ post.get_absolute_url }}" title="Goto last post"><img src="{{ MEDIA_URL }}icons/note_go.png" alt="Goto last post" />
-<a href="{{ post.get_absolute_url }}" title="Goto last post">{{ post.update_date|date:"M d, Y H:i"}}</a><br />
+<a href="{{ post.get_absolute_url }}" title="Goto last post">{{ post.creation_date|date:"M d, Y H:i"}}</a><br />
 <a href="{% url bio-view_profile username=post.user.username %}" title="View profile for {{ post.user.username }}">{{ post.user.username }}</a>
 {% else %}
 <i>No posts</i>
--- a/gpp/templates/forums/topic.html	Sun Oct 11 20:27:07 2009 +0000
+++ b/gpp/templates/forums/topic.html	Thu Oct 22 02:57:18 2009 +0000
@@ -47,6 +47,8 @@
    </form>
    <a href="{% url forums-mod_topic_move topic.id %}"><img src="{{ MEDIA_URL }}icons/application_go.png" alt="Move Topic" title="Move Topic" /></a>
    <a href="{% url forums-mod_topic_move topic.id %}">Move this topic</a>
+   <a href="{% url forums-mod_topic_split topic.id %}"><img src="{{ MEDIA_URL }}icons/arrow_branch.png" alt="Split Topic" title="Split Topic" /></a>
+   <a href="{% url forums-mod_topic_split topic.id %}">Split this topic</a>
 </div>
 {% endif %}
 
--- a/media/css/base.css	Sun Oct 11 20:27:07 2009 +0000
+++ b/media/css/base.css	Thu Oct 22 02:57:18 2009 +0000
@@ -217,6 +217,17 @@
    width:95%;
    border-bottom: 1px solid black;
 }
+td.forum-post-body-split {
+   vertical-align: top;
+   width:90%;
+   border-bottom: 1px solid black;
+}
+td.forum-post-split-check {
+   width:5%;
+   border-left: 1px solid #ccc;
+   border-bottom: 1px solid black;
+   vertical-align: middle;
+}
 div.forum-post-info {
    padding: 2px;
    font-size:.8em;
Binary file media/icons/arrow_branch.png has changed