|
@@ -1,12 +1,15 @@
|
|
|
from django.core.urlresolvers import reverse
|
|
|
+from django import forms
|
|
|
+from django.forms import ValidationError
|
|
|
from django.shortcuts import redirect
|
|
|
from django.template import RequestContext
|
|
|
from django.utils.translation import ugettext as _
|
|
|
from misago.acl.utils import ACLError403, ACLError404
|
|
|
-from misago.forms import FormFields
|
|
|
+from misago.forms import Form, FormLayout, FormFields
|
|
|
from misago.forums.models import Forum
|
|
|
+from misago.messages import Message
|
|
|
from misago.readstracker.trackers import ThreadsTracker
|
|
|
-from misago.threads.forms import QuickReplyForm
|
|
|
+from misago.threads.forms import MoveThreadsForm, QuickReplyForm
|
|
|
from misago.threads.models import Thread, Post
|
|
|
from misago.threads.views.base import BaseView
|
|
|
from misago.views import error403, error404
|
|
@@ -40,7 +43,195 @@ class ThreadView(BaseView):
|
|
|
if not self.tracker.is_read(self.thread):
|
|
|
self.tracker.set_read(self.thread, last_post)
|
|
|
self.tracker.sync()
|
|
|
-
|
|
|
+
|
|
|
+ def get_thread_actions(self):
|
|
|
+ acl = self.request.acl.threads.get_role(self.thread.forum_id)
|
|
|
+ actions = []
|
|
|
+ try:
|
|
|
+ if acl['can_approve'] and self.thread.moderated:
|
|
|
+ actions.append(('accept', _('Accept this thread')))
|
|
|
+ if acl['can_pin_threads'] == 2 and self.thread.weight < 2:
|
|
|
+ actions.append(('annouce', _('Change this thread to annoucement')))
|
|
|
+ if acl['can_pin_threads'] > 0 and self.thread.weight != 1:
|
|
|
+ actions.append(('sticky', _('Change this thread to sticky')))
|
|
|
+ if acl['can_pin_threads'] > 0:
|
|
|
+ if self.thread.weight == 2:
|
|
|
+ actions.append(('normal', _('Change this thread to normal')))
|
|
|
+ if self.thread.weight == 1:
|
|
|
+ actions.append(('normal', _('Unpin this thread')))
|
|
|
+ if acl['can_move_threads_posts']:
|
|
|
+ actions.append(('move', _('Move this thread')))
|
|
|
+ if acl['can_close_threads']:
|
|
|
+ if self.thread.closed:
|
|
|
+ actions.append(('open', _('Open this thread')))
|
|
|
+ else:
|
|
|
+ actions.append(('close', _('Close this thread')))
|
|
|
+ if acl['can_delete_threads']:
|
|
|
+ if self.thread.deleted:
|
|
|
+ actions.append(('undelete', _('Undelete this thread')))
|
|
|
+ else:
|
|
|
+ actions.append(('soft', _('Soft delete this thread')))
|
|
|
+ if acl['can_delete_threads'] == 2:
|
|
|
+ actions.append(('hard', _('Hard delete this thread')))
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ return actions
|
|
|
+
|
|
|
+ def make_thread_form(self):
|
|
|
+ self.thread_form = None
|
|
|
+ list_choices = self.get_thread_actions();
|
|
|
+ if (not self.request.user.is_authenticated()
|
|
|
+ or not list_choices):
|
|
|
+ return
|
|
|
+ form_fields = {'thread_action': forms.ChoiceField(choices=list_choices)}
|
|
|
+ self.thread_form = type('ThreadViewForm', (Form,), form_fields)
|
|
|
+
|
|
|
+ def handle_thread_form(self):
|
|
|
+ if self.request.method == 'POST' and self.request.POST.get('origin') == 'thread_form':
|
|
|
+ self.thread_form = self.thread_form(self.request.POST, request=self.request)
|
|
|
+ if self.thread_form.is_valid():
|
|
|
+ form_action = getattr(self, 'thread_action_' + self.thread_form.cleaned_data['thread_action'])
|
|
|
+ try:
|
|
|
+ response = form_action()
|
|
|
+ if response:
|
|
|
+ return response
|
|
|
+ return redirect(self.request.path)
|
|
|
+ except forms.ValidationError as e:
|
|
|
+ self.message = Message(e.messages[0], 'error')
|
|
|
+ else:
|
|
|
+ if 'thread_action' in self.thread_form.errors:
|
|
|
+ self.message = Message(_("Action requested is incorrect."), 'error')
|
|
|
+ else:
|
|
|
+ self.message = Message(form.non_field_errors()[0], 'error')
|
|
|
+ else:
|
|
|
+ self.thread_form = self.thread_form(request=self.request)
|
|
|
+
|
|
|
+ def thread_action_accept(self):
|
|
|
+ # Sync thread and post
|
|
|
+ self.thread.moderated = False
|
|
|
+ self.thread.replies_moderated -= 1
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.thread.start_post.moderated = False
|
|
|
+ self.thread.start_post.save(force_update=True)
|
|
|
+ self.thread.last_post.set_checkpoint(self.request, 'accepted')
|
|
|
+ # Sync user
|
|
|
+ if self.thread.last_post.user:
|
|
|
+ self.thread.start_post.user.threads += 1
|
|
|
+ self.thread.start_post.user.posts += 1
|
|
|
+ self.thread.start_post.user.save(force_update=True)
|
|
|
+ # Sync forum
|
|
|
+ self.forum.threads_delta += 1
|
|
|
+ self.forum.posts_delta += self.thread.replies + 1
|
|
|
+ self.forum.sync()
|
|
|
+ self.forum.save(force_update=True)
|
|
|
+ # Update monitor
|
|
|
+ self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
|
|
|
+ self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been marked as reviewed and made visible to other members.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_annouce(self):
|
|
|
+ self.thread.weight = 2
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been turned into annoucement.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_sticky(self):
|
|
|
+ self.thread.weight = 1
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been turned into sticky.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_normal(self):
|
|
|
+ self.thread.weight = 0
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.request.messages.set_flash(Message(_('Thread weight has been changed to normal.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_move(self):
|
|
|
+ message = None
|
|
|
+ if self.request.POST.get('do') == 'move':
|
|
|
+ form = MoveThreadsForm(self.request.POST,request=self.request,forum=self.forum)
|
|
|
+ if form.is_valid():
|
|
|
+ new_forum = form.cleaned_data['new_forum']
|
|
|
+ self.thread.forum = new_forum
|
|
|
+ self.thread.post_set.update(forum=new_forum)
|
|
|
+ self.thread.change_set.update(forum=new_forum)
|
|
|
+ self.thread.checkpoint_set.update(forum=new_forum)
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.forum.sync()
|
|
|
+ self.forum.save(force_update=True)
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been moved to "%(forum)s".') % {'forum': new_forum.name}), 'success', 'threads')
|
|
|
+ return None
|
|
|
+ message = Message(form.non_field_errors()[0], 'error')
|
|
|
+ else:
|
|
|
+ form = MoveThreadsForm(request=self.request,forum=self.forum)
|
|
|
+ return self.request.theme.render_to_response('threads/move.html',
|
|
|
+ {
|
|
|
+ 'message': message,
|
|
|
+ 'forum': self.forum,
|
|
|
+ 'parents': self.parents,
|
|
|
+ 'thread': self.thread,
|
|
|
+ 'form': FormLayout(form),
|
|
|
+ },
|
|
|
+ context_instance=RequestContext(self.request));
|
|
|
+
|
|
|
+ def thread_action_open(self):
|
|
|
+ self.thread.closed = False
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.thread.last_post.set_checkpoint(self.request, 'opened')
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been opened.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_close(self):
|
|
|
+ self.thread.closed = True
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ self.thread.last_post.set_checkpoint(self.request, 'closed')
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been closed.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_undelete(self):
|
|
|
+ # Update thread
|
|
|
+ self.thread.deleted = False
|
|
|
+ self.thread.replies_deleted -= 1
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ # Update first post in thread
|
|
|
+ self.thread.start_post.deleted = False
|
|
|
+ self.thread.start_post.save(force_update=True)
|
|
|
+ # Set checkpoint
|
|
|
+ self.thread.last_post.set_checkpoint(self.request, 'undeleted')
|
|
|
+ # Update forum
|
|
|
+ self.forum.sync()
|
|
|
+ self.forum.save(force_update=True)
|
|
|
+ # Update monitor
|
|
|
+ self.request.monitor['threads'] = int(self.request.monitor['threads']) + 1
|
|
|
+ self.request.monitor['posts'] = int(self.request.monitor['posts']) + self.thread.replies + 1
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been undeleted.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_soft(self):
|
|
|
+ # Update thread
|
|
|
+ self.thread.deleted = True
|
|
|
+ self.thread.replies_deleted += 1
|
|
|
+ self.thread.save(force_update=True)
|
|
|
+ # Update first post in thread
|
|
|
+ self.thread.start_post.deleted = True
|
|
|
+ self.thread.start_post.save(force_update=True)
|
|
|
+ # Set checkpoint
|
|
|
+ self.thread.last_post.set_checkpoint(self.request, 'deleted')
|
|
|
+ # Update forum
|
|
|
+ self.forum.sync()
|
|
|
+ self.forum.save(force_update=True)
|
|
|
+ # Update monitor
|
|
|
+ self.request.monitor['threads'] = int(self.request.monitor['threads']) - 1
|
|
|
+ self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
|
|
|
+ self.request.messages.set_flash(Message(_('Thread has been deleted.')), 'success', 'threads')
|
|
|
+
|
|
|
+ def thread_action_hard(self):
|
|
|
+ # Delete thread
|
|
|
+ self.thread.delete()
|
|
|
+ # Update forum
|
|
|
+ self.forum.sync()
|
|
|
+ self.forum.save(force_update=True)
|
|
|
+ # Update monitor
|
|
|
+ self.request.monitor['threads'] = int(self.request.monitor['threads']) - 1
|
|
|
+ self.request.monitor['posts'] = int(self.request.monitor['posts']) - self.thread.replies - 1
|
|
|
+ self.request.messages.set_flash(Message(_('Thread "%(thread)s" has been deleted.') % {'thread': self.thread.name}), 'success', 'threads')
|
|
|
+ return redirect(reverse('forum', kwargs={'forum': self.forum.pk, 'slug': self.forum.slug}))
|
|
|
+
|
|
|
def __call__(self, request, slug=None, thread=None, page=0):
|
|
|
self.request = request
|
|
|
self.pagination = None
|
|
@@ -48,6 +239,11 @@ class ThreadView(BaseView):
|
|
|
try:
|
|
|
self.fetch_thread(thread)
|
|
|
self.fetch_posts(page)
|
|
|
+ self.make_thread_form()
|
|
|
+ if self.thread_form:
|
|
|
+ response = self.handle_thread_form()
|
|
|
+ if response:
|
|
|
+ return response
|
|
|
except Thread.DoesNotExist:
|
|
|
return error404(self.request)
|
|
|
except ACLError403 as e:
|
|
@@ -66,6 +262,7 @@ class ThreadView(BaseView):
|
|
|
'count': self.count,
|
|
|
'posts': self.posts,
|
|
|
'pagination': self.pagination,
|
|
|
- 'quick_reply': FormFields(QuickReplyForm(request=request)).fields
|
|
|
+ 'quick_reply': FormFields(QuickReplyForm(request=request)).fields,
|
|
|
+ 'thread_form': FormFields(self.thread_form).fields if self.thread_form else None,
|
|
|
},
|
|
|
context_instance=RequestContext(request));
|