Mercurial > public > sg101
changeset 111:e5faf9f0c11a
Forums: implemented the bulk moderator functions that operate on a forum: bulk sticky, lock, delete, and move. These haven't been tested that well yet.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Mon, 28 Sep 2009 03:57:09 +0000 |
parents | c329bfaed4a7 |
children | d1b0b86441c0 |
files | gpp/forums/forms.py gpp/forums/urls.py gpp/forums/views.py gpp/templates/forums/forum_index.html gpp/templates/forums/mod_forum.html media/css/base.css |
diffstat | 6 files changed, 206 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/gpp/forums/forms.py Sat Sep 26 20:19:45 2009 +0000 +++ b/gpp/forums/forms.py Mon Sep 28 03:57:09 2009 +0000 @@ -109,14 +109,20 @@ class MoveTopicForm(forms.Form): - """ - Form for a moderator to move a topic to a forum. - """ - forums = forms.ModelChoiceField(label='Move to forum', - queryset=Forum.objects.none()) + """ + Form for a moderator to move a topic to a forum. + """ + forums = forms.ModelChoiceField(label='Move to forum', + queryset=Forum.objects.none()) - def __init__(self, user, *args, **kwargs): - super(MoveTopicForm, self).__init__(*args, **kwargs) - self.fields['forums'].queryset = \ - Forum.objects.forums_for_user(user).order_by('name') + def __init__(self, user, *args, **kwargs): + hide_label = kwargs.pop('hide_label', False) + required = kwargs.pop('required', True) + super(MoveTopicForm, self).__init__(*args, **kwargs) + self.fields['forums'].queryset = \ + Forum.objects.forums_for_user(user).order_by('name') + if hide_label: + self.fields['forums'].label = '' + self.fields['forums'].required = required + print '#############', required
--- a/gpp/forums/urls.py Sat Sep 26 20:19:45 2009 +0000 +++ b/gpp/forums/urls.py Mon Sep 28 03:57:09 2009 +0000 @@ -12,6 +12,7 @@ url(r'^flag-post/$', 'flag_post', name='forums-flag_post'), url(r'^forum/(?P<slug>[\w\d-]+)/$', 'forum_index', name='forums-forum_index'), url(r'^forum/(?P<slug>[\w\d-]+)/new-topic/$', 'new_topic', name='forums-new_topic'), + url(r'^mod/forum/(?P<slug>[\w\d-]+)/$', 'mod_forum', name='forums-mod_forum'), 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'),
--- a/gpp/forums/views.py Sat Sep 26 20:19:45 2009 +0000 +++ b/gpp/forums/views.py Mon Sep 28 03:57:09 2009 +0000 @@ -78,11 +78,14 @@ # we do this for the template since it is rendered twice page_nav = render_to_string('forums/pagination.html', {'page': page}) + + can_moderate = _can_moderate(forum, request.user) return render_to_response('forums/forum_index.html', { 'forum': forum, 'page': page, 'page_nav': page_nav, + 'can_moderate': can_moderate, }, context_instance=RequestContext(request)) @@ -443,17 +446,7 @@ if form.is_valid(): new_forum = form.cleaned_data['forums'] old_forum = topic.forum - if new_forum != old_forum: - topic.forum = new_forum - topic.save() - # Have to adjust foreign keys to last_post, denormalized counts, etc.: - old_forum.topic_count_update() - old_forum.post_count_update() - old_forum.save() - new_forum.topic_count_update() - new_forum.post_count_update() - new_forum.save() - + _move_topic(topic, old_forum, new_forum) return HttpResponseRedirect(topic.get_absolute_url()) else: form = MoveTopicForm(request.user) @@ -466,6 +459,62 @@ context_instance=RequestContext(request)) +@login_required +def mod_forum(request, slug): + """ + Displays a view to allow moderators to perform various operations + on topics in a forum in bulk. We currently support mass locking/unlocking, + stickying and unstickying, moving, and deleting topics. + """ + forum = get_object_or_404(Forum.objects.select_related(), slug=slug) + if not _can_moderate(forum, request.user): + return HttpResponseForbidden() + + topics = forum.topics.select_related('user', 'last_post', 'last_post__user') + paginator = create_topic_paginator(topics) + page_num = int(request.REQUEST.get('page', 1)) + try: + page = paginator.page(page_num) + except InvalidPage: + raise Http404 + + # we do this for the template since it is rendered twice + page_nav = render_to_string('forums/pagination.html', {'page': page}) + form = None + + if request.method == 'POST': + topic_ids = request.POST.getlist('topic_ids') + url = reverse('forums-mod_forum', kwargs={'slug':forum.slug}) + url += '?page=%s' % page_num + + if len(topic_ids): + if request.POST.get('sticky'): + _bulk_sticky(forum, topic_ids) + return HttpResponseRedirect(url) + elif request.POST.get('lock'): + _bulk_lock(forum, topic_ids) + return HttpResponseRedirect(url) + elif request.POST.get('delete'): + _bulk_delete(forum, topic_ids) + return HttpResponseRedirect(url) + elif request.POST.get('move'): + form = MoveTopicForm(request.user, request.POST, hide_label=True) + if form.is_valid(): + _bulk_move(topic_ids, forum, form.cleaned_data['forums']) + return HttpResponseRedirect(url) + + if form is None: + form = MoveTopicForm(request.user, hide_label=True) + + return render_to_response('forums/mod_forum.html', { + 'forum': forum, + 'page': page, + 'page_nav': page_nav, + 'form': form, + }, + context_instance=RequestContext(request)) + + def _can_moderate(forum, user): """ Determines if a user has permission to moderate a given forum. @@ -493,12 +542,68 @@ def _quote_message(who, message): - """ - Builds a message reply by quoting the existing message in a - typical email-like fashion. The quoting is compatible with Markdown. - """ - header = '*%s wrote:*\n\n' % (who, ) - lines = wrap(message, 55).split('\n') - for i, line in enumerate(lines): - lines[i] = '> ' + line - return header + '\n'.join(lines) + """ + Builds a message reply by quoting the existing message in a + typical email-like fashion. The quoting is compatible with Markdown. + """ + header = '*%s wrote:*\n\n' % (who, ) + lines = wrap(message, 55).split('\n') + for i, line in enumerate(lines): + lines[i] = '> ' + line + return header + '\n'.join(lines) + + +def _move_topic(topic, old_forum, new_forum): + if new_forum != old_forum: + topic.forum = new_forum + topic.save() + # Have to adjust foreign keys to last_post, denormalized counts, etc.: + old_forum.topic_count_update() + old_forum.post_count_update() + old_forum.save() + new_forum.topic_count_update() + new_forum.post_count_update() + new_forum.save() + + +def _bulk_sticky(forum, topic_ids): + """ + Performs a toggle on the sticky status for a given list of topic ids. + """ + topics = Topic.objects.filter(pk__in=topic_ids) + for topic in topics: + if topic.forum == forum: + topic.sticky = not topic.sticky + topic.save() + + +def _bulk_lock(forum, topic_ids): + """ + Performs a toggle on the locked status for a given list of topic ids. + """ + topics = Topic.objects.filter(pk__in=topic_ids) + for topic in topics: + if topic.forum == forum: + topic.locked = not topic.locked + topic.save() + + +def _bulk_delete(forum, topic_ids): + """ + Deletes the list of topics. + """ + topics = Topic.objects.filter(pk__in=topic_ids).select_related() + for topic in topics: + if topic.forum == forum: + _delete_topic(topic) + + +def _bulk_move(topic_ids, old_forum, new_forum): + """ + Moves the list of topics to a new forum. + """ + topics = Topic.objects.filter(pk__in=topic_ids).select_related() + for topic in topics: + if topic.forum == old_forum: + _move_topic(topic, old_forum, new_forum) +
--- a/gpp/templates/forums/forum_index.html Sat Sep 26 20:19:45 2009 +0000 +++ b/gpp/templates/forums/forum_index.html Mon Sep 28 03:57:09 2009 +0000 @@ -38,7 +38,7 @@ </tr> {% empty %} <tr> - <td colspan="4"> + <td colspan="5"> <i>No topics available.</i> </td> </tr> @@ -46,5 +46,6 @@ </tbody> </table> {{ page_nav }} +<p><a href="{% url forums-mod_forum slug=forum.slug %}">Moderate this forum</a></p> </div> {% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/forums/mod_forum.html Mon Sep 28 03:57:09 2009 +0000 @@ -0,0 +1,59 @@ +{% extends 'base.html' %} +{% load forum_tags %} +{% block title %}Moderate Forum: {{ forum.name }}{% endblock %} +{% block content %} +<h2>Moderate Forum: {{ forum.name }}</h2> + +<h3> + <a href="{% url forums-index %}">SurfGuitar101 Forum Index</a> » + <a href="{% url forums-forum_index slug=forum.slug %}">{{ forum.name }}</a> +</h3> + +<div class="forum-block"> +{{ page_nav }} +<form action="." method="post"> +<table class="forum-index-table"> + <thead> + <tr> + <th class="forum-index_title">Topics</th> + <th class="forum-index_replies">Replies</th> + <th class="forum-index_author">Author</th> + <th class="forum-index_last_post">Last Post</th> + <th class="forum-index_select">Select<br /><input type="checkbox" id="forums-master-topic" /></th> + </tr> + </thead> + <tbody> + {% for topic in page.object_list %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{% if topic.sticky %}<img src="{{ MEDIA_URL }}icons/asterisk_orange.png" alt="Sticky" title="Sticky" class="forums-topic-icon" />{% endif %} + {% if topic.locked %}<img src="{{ MEDIA_URL }}icons/lock.png" alt="Locked" title="Locked" + class="forums-topic-icon" />{% endif %} + <h4><a href="{{ topic.get_absolute_url }}">{{ topic.name }}</a></h4></td> + <td class="forum-index_replies">{{ topic.reply_count }}</td> + <td class="forum-index_author"><a href="{% url bio-view_profile username=topic.user.username %}" title="View profile for {{ topic.user.username }}">{{ topic.user.username }}</a></td> + <td class="forum-index_last_post"> + {% last_post_info topic.last_post MEDIA_URL %} + </td> + <td class="forum-index_select"><input type="checkbox" name="topic_ids" value="{{ topic.id }}" /></td> + </tr> + {% empty %} + <tr> + <td colspan="5"> + <i>No topics available.</i> + </td> + </tr> + {% endfor %} + </tbody> +</table> +{{ page_nav }} +<div class="forum-mod-controls"> + <input type="submit" value="Toggle Sticky" name="sticky" /> + <input type="submit" value="Toggle Lock" name="lock" /> + <input type="submit" value="Delete" name="delete" /><br /> + <input type="submit" value="Move To:" name="move" /> + {{ form }} + <input type="hidden" name="page" value="{{ page.number }}" /> +</div> +</form> +</div> +{% endblock %}
--- a/media/css/base.css Sat Sep 26 20:19:45 2009 +0000 +++ b/media/css/base.css Mon Sep 28 03:57:09 2009 +0000 @@ -194,6 +194,10 @@ width:20%; text-align:center; } +table.forum-index-table .forum-index_select { + width:10%; + text-align:center; +} table.forum-topic { border-top:1px solid black; border-left:1px solid black;