import hashlib from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect 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 from boards.models import Post, Tag, Ban, User, RANK_USER, NO_PARENT from boards import authors 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) 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).count() > 0 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 = tag_name.strip() if len(tag_name) > 0: tag, created = Tag.objects.get_or_create(name=tag_name) tags.append(tag) # TODO Add a possibility to define a link image instead of an image file. # If a link is given, download the image automatically. 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) 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 (posts without a parent).""" 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) if form.is_valid(): return _new_post(request, form) 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) 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() 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) 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) if request.method == 'POST': form = SettingsForm(request.POST) if form.is_valid(): selected_theme = form.cleaned_data['theme'] user = _get_user(request) user.save_setting('theme', selected_theme) return redirect(settings) else: selected_theme = _get_theme(request) form = SettingsForm(initial={'theme': selected_theme}) 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): context = _init_default_context(request) context['authors'] = boards.authors.authors return render(request, 'boards/authors.html', context) def delete(request, post_id): 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): 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): context = _init_default_context(request) return render(request, 'boards/staticpages/banned.html', context) def page_404(request): context = _init_default_context(request) return render(request, 'boards/404.html', context) def tag_subscribe(request, tag_name): 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): 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): context = _init_default_context(request) return render(request, 'boards/staticpages/' + name + '.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 _get_client_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[-1].strip() else: ip = request.META.get('REMOTE_ADDR') return ip 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() context['theme'] = _get_theme(request, user) return context def _get_user(request): """Get current user from the session""" 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, last_access_time=time_now) session['user_id'] = user.id else: user = User.objects.get(id=session['user_id']) user.last_access_time = timezone.now() user.save() return user def _redirect_to_next(request): if 'next' in request.GET: next_page = request.GET['next'] return HttpResponseRedirect(next_page) else: return redirect(index)