|
|
from django.core.urlresolvers import reverse
|
|
|
from django.core.files import File
|
|
|
from django.core.files.temp import NamedTemporaryFile
|
|
|
from django.core.paginator import EmptyPage
|
|
|
from django.db import transaction
|
|
|
from django.http import Http404
|
|
|
from django.shortcuts import render, redirect
|
|
|
from django.utils.decorators import method_decorator
|
|
|
from django.views.decorators.csrf import csrf_protect
|
|
|
|
|
|
from boards import utils, settings
|
|
|
from boards.abstracts.paginator import get_paginator
|
|
|
from boards.abstracts.settingsmanager import get_settings_manager,\
|
|
|
SETTING_ONLY_FAVORITES
|
|
|
from boards.forms import ThreadForm, PlainErrorList
|
|
|
from boards.models import Post, Thread, Ban
|
|
|
from boards.views.banned import BannedView
|
|
|
from boards.views.base import BaseBoardView, CONTEXT_FORM
|
|
|
from boards.views.posting_mixin import PostMixin
|
|
|
from boards.views.mixins import FileUploadMixin, PaginatedMixin,\
|
|
|
DispatcherMixin, PARAMETER_METHOD
|
|
|
|
|
|
FORM_TAGS = 'tags'
|
|
|
FORM_TEXT = 'text'
|
|
|
FORM_TITLE = 'title'
|
|
|
FORM_IMAGE = 'image'
|
|
|
FORM_THREADS = 'threads'
|
|
|
|
|
|
TAG_DELIMITER = ' '
|
|
|
|
|
|
PARAMETER_CURRENT_PAGE = 'current_page'
|
|
|
PARAMETER_PAGINATOR = 'paginator'
|
|
|
PARAMETER_THREADS = 'threads'
|
|
|
PARAMETER_ADDITIONAL = 'additional_params'
|
|
|
PARAMETER_MAX_FILE_SIZE = 'max_file_size'
|
|
|
PARAMETER_RSS_URL = 'rss_url'
|
|
|
|
|
|
TEMPLATE = 'boards/all_threads.html'
|
|
|
DEFAULT_PAGE = 1
|
|
|
|
|
|
FORM_TAGS = 'tags'
|
|
|
|
|
|
|
|
|
class AllThreadsView(PostMixin, FileUploadMixin, BaseBoardView, PaginatedMixin, DispatcherMixin):
|
|
|
|
|
|
tag_name = ''
|
|
|
|
|
|
def __init__(self):
|
|
|
self.settings_manager = None
|
|
|
super(AllThreadsView, self).__init__()
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
def get(self, request, form: ThreadForm=None):
|
|
|
page = request.GET.get('page', DEFAULT_PAGE)
|
|
|
|
|
|
params = self.get_context_data(request=request)
|
|
|
|
|
|
if not form:
|
|
|
form = ThreadForm(error_class=PlainErrorList,
|
|
|
initial={FORM_TAGS: self.tag_name})
|
|
|
|
|
|
self.settings_manager = get_settings_manager(request)
|
|
|
|
|
|
threads = self.get_threads()
|
|
|
|
|
|
order = request.GET.get('order', 'bump')
|
|
|
if order == 'bump':
|
|
|
threads = threads.order_by('-bump_time')
|
|
|
else:
|
|
|
threads = threads.filter(replies__opening=True)\
|
|
|
.order_by('-replies__pub_time')
|
|
|
filter = request.GET.get('filter')
|
|
|
threads = threads.distinct()
|
|
|
|
|
|
paginator = get_paginator(threads,
|
|
|
settings.get_int('View', 'ThreadsPerPage'))
|
|
|
paginator.current_page = int(page)
|
|
|
|
|
|
try:
|
|
|
threads = paginator.page(page).object_list
|
|
|
except EmptyPage:
|
|
|
raise Http404()
|
|
|
|
|
|
params[PARAMETER_THREADS] = threads
|
|
|
params[CONTEXT_FORM] = form
|
|
|
params[PARAMETER_MAX_FILE_SIZE] = self.get_max_upload_size()
|
|
|
params[PARAMETER_RSS_URL] = self.get_rss_url()
|
|
|
|
|
|
paginator.set_url(self.get_reverse_url(), request.GET.dict())
|
|
|
self.get_page_context(paginator, params, page)
|
|
|
|
|
|
return render(request, TEMPLATE, params)
|
|
|
|
|
|
@method_decorator(csrf_protect)
|
|
|
def post(self, request):
|
|
|
if PARAMETER_METHOD in request.POST:
|
|
|
self.dispatch_method(request)
|
|
|
|
|
|
return redirect('index') # FIXME Different for different modes
|
|
|
|
|
|
form = ThreadForm(request.POST, request.FILES,
|
|
|
error_class=PlainErrorList)
|
|
|
form.session = request.session
|
|
|
|
|
|
if form.is_valid():
|
|
|
return self.create_thread(request, form)
|
|
|
if form.need_to_ban:
|
|
|
# Ban user because he is suspected to be a bot
|
|
|
self._ban_current_user(request)
|
|
|
|
|
|
return self.get(request, form)
|
|
|
|
|
|
def get_page_context(self, paginator, params, page):
|
|
|
"""
|
|
|
Get pagination context variables
|
|
|
"""
|
|
|
|
|
|
params[PARAMETER_PAGINATOR] = paginator
|
|
|
current_page = paginator.page(int(page))
|
|
|
params[PARAMETER_CURRENT_PAGE] = current_page
|
|
|
self.set_page_urls(paginator, params)
|
|
|
|
|
|
def get_reverse_url(self):
|
|
|
return reverse('index')
|
|
|
|
|
|
@transaction.atomic
|
|
|
def create_thread(self, request, form: ThreadForm, html_response=True):
|
|
|
"""
|
|
|
Creates a new thread with an opening post.
|
|
|
"""
|
|
|
|
|
|
ip = utils.get_client_ip(request)
|
|
|
is_banned = Ban.objects.filter(ip=ip).exists()
|
|
|
|
|
|
if is_banned:
|
|
|
if html_response:
|
|
|
return redirect(BannedView().as_view())
|
|
|
else:
|
|
|
return
|
|
|
|
|
|
data = form.cleaned_data
|
|
|
|
|
|
title = form.get_title()
|
|
|
text = data[FORM_TEXT]
|
|
|
files = form.get_files()
|
|
|
file_urls = form.get_file_urls()
|
|
|
images = form.get_images()
|
|
|
|
|
|
text = self._remove_invalid_links(text)
|
|
|
|
|
|
tags = data[FORM_TAGS]
|
|
|
monochrome = form.is_monochrome()
|
|
|
|
|
|
post = Post.objects.create_post(title=title, text=text, files=files,
|
|
|
ip=ip, tags=tags,
|
|
|
tripcode=form.get_tripcode(),
|
|
|
monochrome=monochrome, images=images,
|
|
|
file_urls = file_urls)
|
|
|
|
|
|
# This is required to update the threads to which posts we have replied
|
|
|
# when creating this one
|
|
|
post.notify_clients()
|
|
|
|
|
|
if form.is_subscribe():
|
|
|
settings_manager = get_settings_manager(request)
|
|
|
settings_manager.add_or_read_fav_thread(post)
|
|
|
|
|
|
if html_response:
|
|
|
return redirect(post.get_absolute_url())
|
|
|
|
|
|
def get_threads(self):
|
|
|
"""
|
|
|
Gets list of threads that will be shown on a page.
|
|
|
"""
|
|
|
|
|
|
threads = Thread.objects\
|
|
|
.exclude(tags__in=self.settings_manager.get_hidden_tags())
|
|
|
if self.settings_manager.get_setting(SETTING_ONLY_FAVORITES):
|
|
|
fav_tags = self.settings_manager.get_fav_tags()
|
|
|
if len(fav_tags) > 0:
|
|
|
threads = threads.filter(tags__in=fav_tags)
|
|
|
|
|
|
return threads
|
|
|
|
|
|
def get_rss_url(self):
|
|
|
return self.get_reverse_url() + 'rss/'
|
|
|
|
|
|
def toggle_fav(self, request):
|
|
|
settings_manager = get_settings_manager(request)
|
|
|
settings_manager.set_setting(SETTING_ONLY_FAVORITES,
|
|
|
not settings_manager.get_setting(SETTING_ONLY_FAVORITES, False))
|
|
|
|