def pin_thread_globally(request, thread): if thread.weight != 2: thread.weight = 2 record_event(request, thread, 'pinned_globally') return True else: return False
def hide_thread(request, thread): if not thread.is_hidden: thread.first_post.is_hidden = True thread.first_post.hidden_by = request.user thread.first_post.hidden_by_name = request.user.username thread.first_post.hidden_by_slug = request.user.slug thread.first_post.hidden_on = timezone.now() thread.first_post.save(update_fields=[ 'is_hidden', 'hidden_by', 'hidden_by_name', 'hidden_by_slug', 'hidden_on', ]) thread.is_hidden = True record_event(request, thread, 'hid') if thread.pk == thread.category.last_thread_id: thread.category.synchronize() thread.category.save() return True else: return False
def open_thread(request, thread): if thread.is_closed: thread.is_closed = False record_event(request, thread, 'opened') return True else: return False
def pin_thread_locally(request, thread): if thread.weight != 1: thread.weight = 1 record_event(request, thread, 'pinned_locally') return True else: return False
def unpin_thread(request, thread): if thread.weight: thread.weight = 0 record_event(request, thread, 'unpinned') return True else: return False
def hide_thread(request, thread): if not thread.is_hidden: thread.first_post.is_hidden = True thread.first_post.hidden_by = request.user thread.first_post.hidden_by_name = request.user.username thread.first_post.hidden_by_slug = request.user.slug thread.first_post.hidden_on = timezone.now() thread.first_post.save( update_fields=[ 'is_hidden', 'hidden_by', 'hidden_by_name', 'hidden_by_slug', 'hidden_on', ] ) thread.is_hidden = True record_event(request, thread, 'hid') if thread.pk == thread.category.last_thread_id: thread.category.synchronize() thread.category.save() return True else: return False
def close_thread(request, thread): if not thread.is_closed: thread.is_closed = True record_event(request, thread, 'closed') return True else: return False
def merge_thread(request, thread, other_thread): thread.merge(other_thread) other_thread.delete() record_event(request, thread, 'merged', { 'merged_thread': other_thread.title, }) return True
def merge_threads(request, validated_data, threads, poll): new_thread = Thread(category=validated_data['category'], started_on=threads[0].started_on, last_post_on=threads[0].last_post_on) new_thread.set_title(validated_data['title']) new_thread.save() if poll: poll.move(new_thread) categories = [] for thread in threads: categories.append(thread.category) new_thread.merge(thread) thread.delete() record_event(request, new_thread, 'merged', { 'merged_thread': thread.title, }, commit=False) new_thread.synchronize() new_thread.save() if validated_data.get('weight') == Thread.WEIGHT_GLOBAL: moderation.pin_thread_globally(request, new_thread) elif validated_data.get('weight'): moderation.pin_thread_locally(request, new_thread) if validated_data.get('is_hidden', False): moderation.hide_thread(request, new_thread) if validated_data.get('is_closed', False): moderation.close_thread(request, new_thread) if new_thread.category not in categories: categories.append(new_thread.category) for category in categories: category.synchronize() category.save() # set extra attrs on thread for UI new_thread.is_read = False new_thread.subscription = None # add top category to thread if validated_data.get('top_category'): categories = list(Category.objects.all_categories().filter( id__in=request.user.acl['visible_categories'])) add_categories_to_items(validated_data['top_category'], categories, [new_thread]) else: new_thread.top_category = None add_acl(request.user, new_thread) return new_thread
def action_takeover(self, request, thread): participants.set_thread_owner(thread, request.user) messages.success(request, _("You are now owner of this thread.")) message = _("%(user)s took over this thread.") record_event(request.user, thread, 'user', message, { 'user': request.user, }) thread.save(update_fields=['has_events'])
def hide_thread(user, thread): if not thread.is_hidden: message = _("%(user)s hid thread.") record_event(user, thread, "eye-slash", message, {'user': user}) thread.is_hidden = True thread.save(update_fields=['has_events', 'is_hidden']) return True else: return False
def unhide_thread(request, thread): if thread.is_hidden: thread.first_post.is_hidden = False thread.first_post.save(update_fields=['is_hidden']) thread.is_hidden = False record_event(request, thread, 'unhid') return True else: return False
def approve_thread(request, thread): if thread.is_unapproved: thread.is_unapproved = False thread.first_post.is_unapproved = False thread.first_post.save(update_fields=['is_unapproved']) record_event(request, thread, 'approved') return True else: return False
def merge_thread(user, thread, other_thread): message = _("%(user)s merged in %(thread)s.") record_event(user, thread, "arrow-right", message, { 'user': user, 'thread': other_thread.title }) thread.merge(other_thread) other_thread.delete() return True
def open_thread(user, thread): if thread.is_closed: message = _("%(user)s opened thread.") record_event(user, thread, "unlock-alt", message, {'user': user}) thread.is_closed = False thread.save(update_fields=['has_events', 'is_closed']) return True else: return False
def unpin_thread(user, thread): if thread.weight: message = _("%(user)s unpinned thread.") record_event(user, thread, "circle", message, {'user': user}) thread.weight = 0 thread.save(update_fields=['has_events', 'weight']) return True else: return False
def unpin_thread(user, thread): if thread.is_pinned: message = _("%(user)s unpinned thread.") record_event(user, thread, "circle", message, {'user': user}) thread.is_pinned = False thread.save(update_fields=['has_events', 'is_pinned']) return True else: return False
def close_thread(user, thread): if not thread.is_closed: message = _("%(user)s closed thread.") record_event(user, thread, "lock", message, {'user': user}) thread.is_closed = True thread.save(update_fields=['has_events', 'is_closed']) return True else: return False
def pin_thread_globally(user, thread): if thread.weight != 2: message = _("%(user)s pinned thread globally.") record_event(user, thread, "bookmark", message, {'user': user}) thread.weight = 2 thread.save(update_fields=['has_events', 'weight']) return True else: return False
def pin_thread(user, thread): if not thread.is_pinned: thread.is_pinned = True message = _("%(user)s pinned thread.") record_event(user, thread, "star", message, {'user': user}) thread.save(update_fields=['has_events', 'is_pinned']) return True else: return False
def merge_threads(request, validated_data, threads, poll): new_thread = Thread( category=validated_data['category'], started_on=threads[0].started_on, last_post_on=threads[0].last_post_on, ) new_thread.set_title(validated_data['title']) new_thread.save() if poll: poll.move(new_thread) categories = [] for thread in threads: categories.append(thread.category) new_thread.merge(thread) thread.delete() record_event( request, new_thread, 'merged', { 'merged_thread': thread.title, }, commit=False, ) new_thread.synchronize() new_thread.save() if validated_data.get('weight') == Thread.WEIGHT_GLOBAL: moderation.pin_thread_globally(request, new_thread) elif validated_data.get('weight'): moderation.pin_thread_locally(request, new_thread) if validated_data.get('is_hidden', False): moderation.hide_thread(request, new_thread) if validated_data.get('is_closed', False): moderation.close_thread(request, new_thread) if new_thread.category not in categories: categories.append(new_thread.category) for category in categories: category.synchronize() category.save() # set extra attrs on thread for UI new_thread.is_read = False new_thread.subscription = None add_acl(request.user, new_thread) return new_thread
def unlabel_thread(user, thread): if thread.label_id: thread.label = None message = _("%(user)s removed thread label.") record_event(user, thread, "tag", message, {'user': user}) thread.save(update_fields=['has_events', 'label']) return True else: return False
def move_thread(user, thread, new_forum): if thread.forum_id != new_forum.pk: message = _("%(user)s moved thread from %(forum)s.") record_event(user, thread, "arrow-right", message, { 'user': user, 'forum': thread.forum }) thread.move(new_forum) thread.save(update_fields=['has_events', 'forum']) return True else: return False
def approve_thread(user, thread): if thread.is_moderated: message = _("%(user)s approved thread.") record_event(user, thread, "check", message, {'user': user}) thread.is_closed = False thread.first_post.is_moderated = False thread.first_post.save(update_fields=['is_moderated']) thread.synchronize() thread.save(update_fields=['has_events', 'is_moderated']) return True else: return False
def move_thread(user, thread, new_category): if thread.category_id != new_category.pk: message = _("%(user)s moved thread from %(category)s.") record_event(user, thread, "arrow-right", message, { 'user': user, 'category': thread.category }) thread.move(new_category) thread.save(update_fields=['has_events', 'category']) return True else: return False
def approve_thread(user, thread): if thread.is_unapproved: message = _("%(user)s approved thread.") record_event(user, thread, "check", message, {'user': user}) thread.is_closed = False thread.first_post.is_unapproved = False thread.first_post.save(update_fields=['is_unapproved']) thread.synchronize() thread.save(update_fields=['has_events', 'is_unapproved']) return True else: return False
def approve_thread(request, thread): if thread.is_unapproved: thread.first_post.is_unapproved = False thread.first_post.save(update_fields=['is_unapproved']) thread.is_unapproved = False unapproved_post_qs = thread.post_set.filter(is_unapproved=True) thread.has_unapproved_posts = unapproved_post_qs.exists() record_event(request, thread, 'approved') return True else: return False
def unhide_thread(user, thread): if thread.is_hidden: message = _("%(user)s made thread visible.") record_event(user, thread, "eye", message, {'user': user}) thread.first_post.is_hidden = False thread.first_post.save(update_fields=['is_hidden']) thread.is_hidden = False thread.save(update_fields=['has_events', 'is_hidden']) thread.synchronize() thread.save() return True else: return False
def unhide_thread(request, thread): if thread.is_hidden: thread.first_post.is_hidden = False thread.first_post.save(update_fields=['is_hidden']) thread.is_hidden = False record_event(request, thread, 'unhid') if thread.pk == thread.category.last_thread_id: thread.category.synchronize() thread.category.save() return True else: return False
def move_thread(request, thread, new_category): if thread.category_id != new_category.pk: from_category = thread.category thread.move(new_category) record_event( request, thread, 'moved', { 'from_category': { 'name': from_category.name, 'url': from_category.get_absolute_url(), }, }) return True else: return False
def move_thread(request, thread, new_category): if thread.category_id != new_category.pk: from_category = thread.category thread.move(new_category) record_event( request, thread, 'moved', { 'from_category': { 'name': from_category.name, 'url': from_category.get_absolute_url(), }, } ) return True else: return False
def dispatch(self, request, *args, **kwargs): thread = self.get_thread(request, lock=True, **kwargs) try: if not request.method == "POST": raise RuntimeError(_("Wrong action received.")) if not thread.participant: raise RuntimeError( _("You have to be thread participant in " "order to be able to leave thread.")) user_qs = thread.threadparticipant_set.select_related('user') try: participant = user_qs.get(user_id=request.user.id) except ThreadParticipant.DoesNotExist: raise RuntimeError( _("You need to be thread " "participant to leave it.")) except RuntimeError as e: messages.error(request, unicode(e)) return redirect(thread.get_absolute_url()) participants.remove_participant(thread, request.user) if not thread.threadparticipant_set.exists(): thread.delete() elif thread.participant.is_owner: new_owner = user_qs.order_by('id')[:1][0].user participants.set_thread_owner(thread, new_owner) message = _("%(user)s left this thread. " "%(new_owner)s is now thread owner.") record_event(request.user, thread, 'user', message, { 'user': request.user, 'new_owner': new_owner }) thread.save(update_fields=['has_events']) else: message = _("%(user)s left this thread.") record_event(request.user, thread, 'user', message, { 'user': request.user, }) thread.save(update_fields=['has_events']) message = _('You have left "%(thread)s" thread.') message = message % {'thread': thread.title} messages.info(request, message) return redirect('misago:private_threads')
def action(self, request, thread, kwargs): user_qs = thread.threadparticipant_set.select_related('user') try: participant = user_qs.get(user_id=kwargs['user_id']) except ThreadParticipant.DoesNotExist: return JsonResponse({ 'message': _("Requested participant couldn't be found."), 'is_error': True, }) if participant.user == request.user: return JsonResponse({ 'message': _('To leave thread use "Leave thread" option.'), 'is_error': True, }) participants_count = len(thread.participants_list) - 1 if participants_count == 0: return JsonResponse({ 'message': _("You can't remove last thread participant."), 'is_error': True, }) participants.remove_participant(thread, participant.user) if not participants.thread_has_participants(thread): thread.delete() else: message = _("%(user)s removed %(participant)s from this thread.") record_event(request.user, thread, 'user', message, { 'user': request.user, 'participant': participant.user }) thread.save(update_fields=['has_events']) participants_count = len(thread.participants_list) - 1 message = ungettext("%(users)s participant", "%(users)s participants", participants_count) message = message % {'users': participants_count} return JsonResponse({'is_error': False, 'message': message})
def change_thread_title(request, thread, new_title): if thread.title != new_title: old_title = thread.title thread.set_title(new_title) thread.save(update_fields=['title', 'slug']) thread.first_post.set_search_document(thread.title) thread.first_post.save(update_fields=['search_document']) thread.first_post.update_search_vector() thread.first_post.save(update_fields=['search_vector']) record_event(request, thread, 'changed_title', {'old_title': old_title}) return True else: return False
def dispatch(self, request, *args, **kwargs): thread = self.get_thread(request, lock=True, **kwargs) try: if not request.method == "POST": raise RuntimeError(_("Wrong action received.")) if not thread.participant: raise RuntimeError(_("You have to be thread participant in " "order to be able to leave thread.")) user_qs = thread.threadparticipant_set.select_related('user') try: participant = user_qs.get(user_id=request.user.id) except ThreadParticipant.DoesNotExist: raise RuntimeError(_("You need to be thread " "participant to leave it.")) except RuntimeError as e: messages.error(request, unicode(e)) return redirect(thread.get_absolute_url()) participants.remove_participant(thread, request.user) if not thread.threadparticipant_set.exists(): thread.delete() elif thread.participant.is_owner: new_owner = user_qs.order_by('id')[:1][0].user participants.set_thread_owner(thread, new_owner) message = _("%(user)s left this thread. " "%(new_owner)s is now thread owner.") record_event(request.user, thread, 'user', message, { 'user': request.user, 'new_owner': new_owner }) thread.save(update_fields=['has_events']) else: message = _("%(user)s left this thread.") record_event(request.user, thread, 'user', message, { 'user': request.user, }) thread.save(update_fields=['has_events']) message = _('You have left "%(thread)s" thread.') message = message % {'thread': thread.title} messages.info(request, message) return redirect('misago:private_threads')
def label_thread(user, thread, label): if not thread.label_id or thread.label_id != label.pk: if thread.label_id: message = _("%(user)s changed thread label to %(label)s.") else: message = _("%(user)s set thread label to %(label)s.") record_event(user, thread, "tag", message, { 'user': user, 'label': label.name }) thread.label = label thread.save(update_fields=['has_events', 'label']) return True else: return False
def change_thread_title(request, thread, new_title): if thread.title != new_title: old_title = thread.title thread.set_title(new_title) thread.save(update_fields=['title', 'slug']) thread.first_post.set_search_document(thread.title) thread.first_post.save(update_fields=['search_document']) thread.first_post.update_search_vector() thread.first_post.save(update_fields=['search_vector']) record_event(request, thread, 'changed_title', { 'old_title': old_title, }) return True else: return False
def test_events_dont_take_space(self): """events dont take space away from posts""" posts_limit = settings.MISAGO_POSTS_PER_PAGE events_limit = settings.MISAGO_EVENTS_PER_PAGE events = [] for _ in range(events_limit + 5): event = record_event(MockRequest(self.user), self.thread, 'closed') events.append(event) posts = [] for _ in range(posts_limit - 1): post = testutils.reply_thread(self.thread) posts.append(post) # test that all events and posts within limits were rendered response = self.client.get(self.thread.get_absolute_url()) for event in events[5:]: self.assertContains(response, event.get_absolute_url()) for post in posts: self.assertContains(response, post.get_absolute_url()) # add second page to thread with more events for _ in range(posts_limit): post = testutils.reply_thread(self.thread) for _ in range(events_limit): event = record_event(MockRequest(self.user), self.thread, 'closed') events.append(event) # see first page response = self.client.get(self.thread.get_absolute_url()) for event in events[5:events_limit]: self.assertContains(response, event.get_absolute_url()) for post in posts[:posts_limit - 1]: self.assertContains(response, post.get_absolute_url()) # see second page response = self.client.get('%s2/' % self.thread.get_absolute_url()) for event in events[5 + events_limit:]: self.assertContains(response, event.get_absolute_url()) for post in posts[posts_limit - 1:]: self.assertContains(response, post.get_absolute_url())
def test_record_event(self): """record_event registers event in thread""" message = "%(user)s has changed this thread to announcement." event = record_event(self.user, self.thread, "announcement", message, { 'user': (u"Łob", self.user.get_absolute_url()) }) self.assertTrue(event.is_valid) self.assertTrue(event.message.endswith(message[8:])) self.assertTrue(self.thread.has_events)
def test_anonymous_user_view_no_showstoppers_display(self): """kitchensink thread view has no showstoppers for anons""" poll = testutils.post_poll(self.thread, self.user) event = record_event(MockRequest(self.user), self.thread, 'closed') hidden_event = record_event(MockRequest(self.user), self.thread, 'opened') hide_post(self.user, hidden_event) unapproved_post = testutils.reply_thread(self.thread, is_unapproved=True) post = testutils.reply_thread(self.thread) self.logout_user() response = self.client.get(self.thread.get_absolute_url()) self.assertContains(response, poll.question) self.assertContains(response, event.get_absolute_url()) self.assertContains(response, post.get_absolute_url()) self.assertNotContains(response, hidden_event.get_absolute_url()) self.assertNotContains(response, unapproved_post.get_absolute_url())