import hashlib import string from django.core import serializers from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.http.response import HttpResponse from django.template import RequestContext from django.shortcuts import render, redirect, get_object_or_404 from django.utils import timezone from boards import forms import boards from boards import utils from boards.forms import ThreadForm, PostForm, SettingsForm, PlainErrorList, \ ThreadCaptchaForm, PostCaptchaForm, LoginForm, ModeratorSettingsForm from boards.models import Post, Tag, Ban, User, RANK_USER, SETTING_MODERATE from boards import authors from boards.utils import get_client_ip import neboard def index(request, page=0): context = _init_default_context(request) if utils.need_include_captcha(request): threadFormClass = ThreadCaptchaForm kwargs = {'request': request} else: threadFormClass = ThreadForm kwargs = {} if request.method == 'POST': form = threadFormClass(request.POST, request.FILES, error_class=PlainErrorList, **kwargs) form.session = request.session if form.is_valid(): return _new_post(request, form) if form.need_to_ban: # Ban user because he is suspected to be a bot _ban_current_user(request) else: form = threadFormClass(error_class=PlainErrorList, **kwargs) threads = [] for thread in Post.objects.get_threads(page=int(page)): threads.append({'thread': thread, 'bumpable': thread.can_bump()}) context['threads'] = None if len(threads) == 0 else threads context['form'] = form context['pages'] = range(Post.objects.get_thread_page_count()) return render(request, 'boards/posting_general.html', context) def _new_post(request, form, thread_id=boards.models.NO_PARENT): """Add a new post (in thread or as a reply).""" ip = get_client_ip(request) is_banned = Ban.objects.filter(ip=ip).exists() if is_banned: return redirect(you_are_banned) data = form.cleaned_data title = data['title'] text = data['text'] if 'image' in data.keys(): image = data['image'] else: image = None tags = [] new_thread = thread_id == boards.models.NO_PARENT if new_thread: tag_strings = data['tags'] if tag_strings: tag_strings = tag_strings.split(' ') for tag_name in tag_strings: tag_name = string.lower(tag_name.strip()) if len(tag_name) > 0: tag, created = Tag.objects.get_or_create(name=tag_name) tags.append(tag) linked_tags = tag.get_linked_tags() if len(linked_tags) > 0: tags.extend(linked_tags) op = None if thread_id == boards.models.NO_PARENT else \ get_object_or_404(Post, id=thread_id) post = Post.objects.create_post(title=title, text=text, ip=ip, thread=op, image=image, tags=tags, user=_get_user(request)) thread_to_show = (post.id if new_thread else thread_id) if new_thread: return redirect(thread, post_id=thread_to_show) else: return redirect(reverse(thread, kwargs={'post_id': thread_to_show}) + '#' + str(post.id)) def tag(request, tag_name, page=0): """ Get all tag threads. Threads are split in pages, so some page is requested. Default page is 0. """ tag = get_object_or_404(Tag, name=tag_name) threads = [] for thread in Post.objects.get_threads(tag=tag, page=int(page)): threads.append({'thread': thread, 'bumpable': thread.can_bump()}) if request.method == 'POST': form = ThreadForm(request.POST, request.FILES, error_class=PlainErrorList) form.session = request.session if form.is_valid(): return _new_post(request, form) if form.need_to_ban: # Ban user because he is suspected to be a bot _ban_current_user(request) else: form = forms.ThreadForm(initial={'tags': tag_name}, error_class=PlainErrorList) context = _init_default_context(request) context['threads'] = None if len(threads) == 0 else threads context['tag'] = tag context['pages'] = range(Post.objects.get_thread_page_count(tag=tag)) context['form'] = form return render(request, 'boards/posting_general.html', context) def thread(request, post_id): """Get all thread posts""" if utils.need_include_captcha(request): postFormClass = PostCaptchaForm kwargs = {'request': request} else: postFormClass = PostForm kwargs = {} if request.method == 'POST': form = postFormClass(request.POST, request.FILES, error_class=PlainErrorList, **kwargs) form.session = request.session if form.is_valid(): return _new_post(request, form, post_id) if form.need_to_ban: # Ban user because he is suspected to be a bot _ban_current_user(request) else: form = postFormClass(error_class=PlainErrorList, **kwargs) posts = Post.objects.get_thread(post_id) context = _init_default_context(request) context['posts'] = posts context['form'] = form context['bumpable'] = posts[0].can_bump() if context['bumpable']: context['posts_left'] = neboard.settings.MAX_POSTS_PER_THREAD - len( posts) context['bumplimit_progress'] = str(float(context['posts_left']) / neboard.settings.MAX_POSTS_PER_THREAD * 100) return render(request, 'boards/thread.html', context) def login(request): """Log in with user id""" context = _init_default_context(request) if request.method == 'POST': form = LoginForm(request.POST, request.FILES, error_class=PlainErrorList) form.session = request.session if form.is_valid(): user = User.objects.get(user_id=form.cleaned_data['user_id']) request.session['user_id'] = user.id return redirect(index) else: form = LoginForm() context['form'] = form return render(request, 'boards/login.html', context) def settings(request): """User's settings""" context = _init_default_context(request) user = _get_user(request) is_moderator = user.is_moderator() if request.method == 'POST': if is_moderator: form = ModeratorSettingsForm(request.POST, error_class=PlainErrorList) else: form = SettingsForm(request.POST, error_class=PlainErrorList) if form.is_valid(): selected_theme = form.cleaned_data['theme'] user.save_setting('theme', selected_theme) if is_moderator: moderate = form.cleaned_data['moderate'] user.save_setting(SETTING_MODERATE, moderate) return redirect(settings) else: selected_theme = _get_theme(request) if is_moderator: form = ModeratorSettingsForm(initial={'theme': selected_theme, 'moderate': context['moderator']}, error_class=PlainErrorList) else: form = SettingsForm(initial={'theme': selected_theme}, error_class=PlainErrorList) context['form'] = form return render(request, 'boards/settings.html', context) def all_tags(request): """All tags list""" context = _init_default_context(request) context['all_tags'] = Tag.objects.get_not_empty_tags() return render(request, 'boards/tags.html', context) def jump_to_post(request, post_id): """Determine thread in which the requested post is and open it's page""" post = get_object_or_404(Post, id=post_id) if not post.thread: return redirect(thread, post_id=post.id) else: return redirect(reverse(thread, kwargs={'post_id': post.thread.id}) + '#' + str(post.id)) def authors(request): """Show authors list""" context = _init_default_context(request) context['authors'] = boards.authors.authors return render(request, 'boards/authors.html', context) def delete(request, post_id): """Delete post""" user = _get_user(request) post = get_object_or_404(Post, id=post_id) if user.is_moderator(): # TODO Show confirmation page before deletion Post.objects.delete_post(post) if not post.thread: return _redirect_to_next(request) else: return redirect(thread, post_id=post.thread.id) def ban(request, post_id): """Ban user""" user = _get_user(request) post = get_object_or_404(Post, id=post_id) if user.is_moderator(): # TODO Show confirmation page before ban Ban.objects.get_or_create(ip=post.poster_ip) return _redirect_to_next(request) def you_are_banned(request): """Show the page that notifies that user is banned""" context = _init_default_context(request) return render(request, 'boards/staticpages/banned.html', context) def page_404(request): """Show page 404 (not found error)""" context = _init_default_context(request) return render(request, 'boards/404.html', context) def tag_subscribe(request, tag_name): """Add tag to favorites""" user = _get_user(request) tag = get_object_or_404(Tag, name=tag_name) if not tag in user.fav_tags.all(): user.fav_tags.add(tag) return _redirect_to_next(request) def tag_unsubscribe(request, tag_name): """Remove tag from favorites""" user = _get_user(request) tag = get_object_or_404(Tag, name=tag_name) if tag in user.fav_tags.all(): user.fav_tags.remove(tag) return _redirect_to_next(request) def static_page(request, name): """Show a static page that needs only tags list and a CSS""" context = _init_default_context(request) return render(request, 'boards/staticpages/' + name + '.html', context) def api_get_post(request, post_id): """ Get the JSON of a post. This can be used as and API for external clients. """ post = get_object_or_404(Post, id=post_id) json = serializers.serialize("json", [post], fields=( "pub_time", "_text_rendered", "title", "text", "image", "image_width", "image_height", "replies", "tags" )) return HttpResponse(content=json) def get_post(request, post_id): """Get the html of a post. Used for popups.""" post = get_object_or_404(Post, id=post_id) context = RequestContext(request) context["post"] = post return render(request, 'boards/post.html', context) def _get_theme(request, user=None): """Get user's CSS theme""" if not user: user = _get_user(request) theme = user.get_setting('theme') if not theme: theme = neboard.settings.DEFAULT_THEME return theme def _init_default_context(request): """Create context with default values that are used in most views""" context = RequestContext(request) user = _get_user(request) context['user'] = user context['tags'] = user.get_sorted_fav_tags() theme = _get_theme(request, user) context['theme'] = theme context['theme_css'] = 'css/' + theme + '/base_page.css' # This shows the moderator panel moderate = user.get_setting(SETTING_MODERATE) if moderate == 'True': context['moderator'] = user.is_moderator() else: context['moderator'] = False return context def _get_user(request): """ Get current user from the session. If the user does not exist, create a new one. """ session = request.session if not 'user_id' in session: request.session.save() md5 = hashlib.md5() md5.update(session.session_key) new_id = md5.hexdigest() time_now = timezone.now() user = User.objects.create(user_id=new_id, rank=RANK_USER, registration_time=time_now) session['user_id'] = user.id else: user = User.objects.get(id=session['user_id']) return user def _redirect_to_next(request): """ If a 'next' parameter was specified, redirect to the next page. This is used when the user is required to return to some page after the current view has finished its work. """ if 'next' in request.GET: next_page = request.GET['next'] return HttpResponseRedirect(next_page) else: return redirect(index) def _ban_current_user(request): """Add current user to the IP ban list""" ip = utils.get_client_ip(request) Ban.objects.get_or_create(ip=ip)