# -*- coding: utf-8 -*- """ Copyright 2012-2014 Grégory Soutadé This file is part of Dynastie. Dynastie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Dynastie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Dynastie. If not, see . """ import os import re from datetime import datetime, date, time from django.shortcuts import render from django.contrib.auth import authenticate, login, logout from django.http import HttpResponseRedirect, HttpResponse, Http404, HttpResponseForbidden from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt from django.forms.models import inlineformset_factory from django.core import mail from django.core.mail import EmailMultiAlternatives from dynastie.models import * from dynastie.forms import * from dynastie.search import * from django.template.defaultfilters import register from django.template import Variable, VariableDoesNotExist @register.filter def hash(object, attr): pseudo_context = { 'object' : object } try: value = Variable('object.%s' % attr).resolve(pseudo_context) except VariableDoesNotExist: value = None return value def have_I_right(request, blog_id=None, post_id=None, must_be_superuser=False, cls=Post): b = None p = None if must_be_superuser and not request.user.is_superuser: raise Http404 if post_id: p = cls.objects.get(pk=post_id) if p is None: raise Http404 blog_id = p.blog.id if blog_id: if not request.user.is_superuser: b = Blog.objects.filter(pk=blog_id, writers=request.user.id) if not b: raise Http404 b = b[0] else: b = Blog.objects.get(pk=blog_id) if b is None: raise Http404 return (b, p) def to_unicode(s): if type(s) == unicode: return s else: return unicode(s, 'utf-8') def createNavigationBar(blog_id, cur_page, nb_pages): if nb_pages == 0: return '' navigation_bar = '' if cur_page == 0: navigation_bar += '<< <' else: navigation_bar += '<< ' % blog_id navigation_bar += '< ' % (blog_id, cur_page-1) for i in range(nb_pages+1): if i == cur_page: navigation_bar += ' %d' % (i+1) else: navigation_bar += ' %d' % (blog_id, i, i+1) if cur_page == nb_pages: navigation_bar += ' > >>' else: navigation_bar += ' >' % (blog_id, cur_page+1) navigation_bar += ' >>' % (blog_id, nb_pages) return navigation_bar def index(request): if request.user.is_authenticated: return HttpResponseRedirect('/blog') login_failed = False if 'login' in request.POST: user = authenticate(username=request.POST['login'], password=request.POST['password']) if user is None: login_failed = True else: login(request, user) if 'next' in request.GET: return HttpResponseRedirect(request.GET['next']) else: return HttpResponseRedirect('/blog') c = {'login_failed' : login_failed} return render(request, 'login.html', c) def disconnect(request): logout(request) return HttpResponseRedirect('/') @login_required def user(request): c = {'users' : User.objects.all()} return render(request, 'user.html', c) @login_required def add_user(request): if not request.user.is_superuser: return HttpResponseRedirect('/user') if request.method == 'POST': if 'add' in request.POST: form = UserForm(request.POST) if form.is_valid(): form = form.save() user = User.objects.get(pk=form.id) user.set_password(request.POST['password']) user.save() return HttpResponseRedirect('/user') else: return HttpResponseRedirect('/user') else: form = UserForm() return render(request, 'add_user.html', {'form': form}) @login_required def edit_user(request, user_id): user = User.objects.get(pk=user_id) if user is None: raise Http404 edited = False if request.method == 'POST': if int(user_id) != int(request.user.id) and (not request.user.is_superuser): return HttpResponseRedirect('/user') if 'edit' in request.POST: form = UserForm(request.POST, instance=user, initial={'password':''}) if form.is_valid(): form.save() if request.POST['password'] != '': user.set_password(request.POST['password']) user.save() edited = True else: if 'delete' in request.POST and request.user.is_superuser: User.objects.get(pk=user_id).delete() return HttpResponseRedirect('/user') if 'cancel' in request.POST: return HttpResponseRedirect('/user') else: form = UserForm(instance=user, initial={'password':''}) c = {'user_to_edit' : user, 'form' : form, 'edited' : edited} return render(request, 'edit_user.html', c) @login_required def category(request, blog_id): b,_ = have_I_right(request, blog_id) categories = Category.objects.filter(blog_id=blog_id) c = {'categories' : categories, 'blog' : b} return render(request, 'category.html', c) @login_required def add_category(request, blog_id): b,_ = have_I_right(request, blog_id) if request.method == 'POST': if 'add' in request.POST: form = CategoryForm(request.POST) form.instance.blog = b if form.is_valid(): form = form.save() return HttpResponseRedirect('/category/' + str(b.id)) else: return HttpResponseRedirect('/category/' + str(b.id)) else: form = CategoryForm() return render(request, 'add_category.html', {'form': form, 'blog' : b}) @login_required def edit_category(request, category_id): category = Category.objects.get(pk=category_id) if category is None: raise Http404 b,_ = have_I_right(request, category.blog.id) if request.method == 'POST': if 'cancel' in request.POST: return HttpResponseRedirect('/category/' + str(b.id)) if 'edit' in request.POST: name = category.name name = name.strip() form = CategoryForm(request.POST, instance=category) if form.is_valid(): if request.POST['name'] != name: category.remove() form.save() return HttpResponseRedirect('/category/' + str(b.id)) else: form = CategoryForm(instance=category) c = {'category' : category, 'form' : form} return render(request, 'edit_category.html', c) @login_required def delete_category(request, category_id): category = Category.objects.get(pk=category_id) if category is None: raise Http404 b,_ = have_I_right(request, category.blog.id) category.delete() return HttpResponseRedirect('/category/' + str(b.id)) @login_required def tag(request, blog_id): b,_ = have_I_right(request, blog_id) tags = Tag.objects.filter(blog_id=blog_id) c = {'tags' : tags, 'blog' : b} return render(request, 'tag.html', c) @login_required def edit_tag(request, tag_id): tag = Tag.objects.get(pk=tag_id) if tag is None: raise Http404 b,_ = have_I_right(request, tag.blog.id) if request.method == 'POST': if 'cancel' in request.POST: return HttpResponseRedirect('/tag/' + str(b.id)) if 'edit' in request.POST: name = tag.name name = name.strip() form = TagForm(request.POST, instance=tag) if form.is_valid(): if request.POST['name'] != name: tag.remove() form.save() return HttpResponseRedirect('/tag/' + str(b.id)) else: form = TagForm(instance=tag) c = {'tag' : tag, 'form' : form} return render(request, 'edit_tag.html', c) @login_required def delete_tag(request, tag_id): tag = Tag.objects.get(pk=tag_id) if tag is None: raise Http404 b,_ = have_I_right(request, tag.blog.id) tag.delete() return HttpResponseRedirect('/tag/' + str(b.id)) @login_required def blog(request): if request.user.is_superuser: b = Blog.objects.all() else: b = Blog.objects.filter(writers=request.user.id) c = {'blogs' : b} return render(request, 'blog.html', c) @login_required def add_blog(request): if not request.user.is_superuser: return HttpResponseRedirect('/blog') if request.method == 'POST': if 'add' in request.POST: form = BlogForm(request.POST) if form.is_valid(): form = form.save() form.create() return HttpResponseRedirect('/blog') else: return HttpResponseRedirect('/blog') else: form = BlogForm() return render(request, 'add_blog.html', {'form': form}) @login_required def view_blog(request, blog_id): b,_ = have_I_right(request, blog_id) posts = Post.objects.filter(blog=b) if 'page' in request.GET: cur_page = int(request.GET['page']) else: cur_page = request.session.get('cur_page',0) if cur_page <= 0: drafts = Draft.objects.filter(blog=b).order_by('-creation_date') else: drafts = [] count = len(posts) - len(drafts) nb_pages = int(count/50) # Prevent error injection if cur_page < 0 : cur_page = 0 if cur_page > nb_pages : cur_page = nb_pages-1 request.session['cur_page'] = cur_page start = cur_page * 50 end = start + 50 + len(drafts) posts = posts.order_by('-creation_date')[start:end] form = BlogForm(instance=b) comments = Comment.objects.all() dict_comments = {} for comment in comments: key = comment.post.id dict_comments[key] = dict_comments.get(key, 0) + 1 navigation_bar = createNavigationBar(b.id, cur_page, nb_pages) c = {'blog' : b, 'posts' : posts, 'drafts' : drafts, 'form' : form, 'comments' : dict_comments, 'navigation_bar' : navigation_bar} return render(request, 'view_blog.html', c) @login_required def edit_blog(request, blog_id): if not request.user.is_superuser: return HttpResponseRedirect('/blog/' + str(blog_id)) b = Blog.objects.get(pk=blog_id) if b is None: raise Http404 edited = False if request.method == 'POST': if 'edit' in request.POST: form = BlogForm(request.POST, instance=b) if form.is_valid(): form.save() edited = True else: if 'delete' in request.POST: b = Blog.objects.get(pk=blog_id) b.delete() return HttpResponseRedirect('/blog') else: form = BlogForm(instance=b) posts = Post.objects.filter(blog=b).order_by('-creation_date') c = {'blog' : b, 'posts' : posts, 'form' : form, 'edited' : edited} return render(request, 'view_blog.html', c) @login_required def search_blog(request, blog_id): from dynastie.generators import search b,_ = have_I_right(request, blog_id) text = request.POST['text'] if text is None or text == '': return HttpResponseRedirect('/blog') s = Search() post_list = s.search(b, text) posts = [] if not post_list is None: post_list = post_list[:50] for post_id in post_list: try: post = Post.objects.get(pk=post_id) except: continue if not post is None: posts.append(post) comments = Comment.objects.all() dict_comments = {} for comment in comments: key = comment.post.id dict_comments[key] = dict_comments.get(key, 0) + 1 c = {'blog' : b, 'posts' : posts, 'comments' : dict_comments} return render(request, 'search_blog.html', c) @login_required def add_post(request, blog_id): (b,_) = have_I_right(request, blog_id) if request.method == 'POST': if 'add' in request.POST: content_format = Post.CONTENT_HTML if request.POST['editor'] == 'text': content_format = Post.CONTENT_TEXT post = Post(blog=Blog.objects.get(pk=blog_id), author=User.objects.get(pk=request.user.id), creation_date=datetime.now(), modification_date=datetime.now(), content_format=content_format) content = request.POST['content'] # del request.POST['content'] form = PostForm(request.POST, instance=post) if form.is_valid(): form = form.save() form.createPost(content, request.POST['text_tags']) s = Search() s.index_post(b, form.id) request.session['cur_page'] = 0 return HttpResponseRedirect('/blog/' + blog_id) elif 'draft' in request.POST: content_format = Post.CONTENT_HTML if request.POST['editor'] == 'text': content_format = Post.CONTENT_TEXT draft = Draft(blog=Blog.objects.get(pk=blog_id), author=User.objects.get(pk=request.user.id), creation_date=datetime.now(), modification_date=datetime.now(), content_format=content_format, published=False) content = request.POST['content'] # del request.POST['content'] form = DraftForm(request.POST, instance=draft) if form.is_valid(): form = form.save() form.createDraft(content, request.POST['text_tags']) request.session['cur_page'] = 0 return HttpResponseRedirect('/blog/' + blog_id) else: return HttpResponseRedirect('/blog/' + blog_id) else: form = PostForm() return render(request, 'add_post.html', { 'form': form, 'blog_id' : blog_id, 'all_tags' : Tag.objects.all().order_by('name'), 'editor' : 'html' }) @login_required def edit_post(request, post_id): (b, post) = have_I_right(request, None, post_id) title = post.title blog_id = b.id if request.method == 'POST': if 'edit' in request.POST: content_format = Post.CONTENT_HTML if request.POST['editor'] == 'text': content_format = Post.CONTENT_TEXT post.content_format = content_format form = PostForm(request.POST, instance=post) if form.is_valid(): if title != request.POST['title']: post.remove() form.save() post.createPost(request.POST['content'], request.POST['text_tags']) s = Search() s.edit_post(b, post_id) return HttpResponseRedirect('/blog/' + str(blog_id)) else: if 'cancel' in request.POST: return HttpResponseRedirect('/blog/' + str(blog_id)) else: form = PostForm(instance=post, initial={'text_tags':', '.join((tag.name) for tag in post.tags.all().order_by('name'))}) filename = b.src_path + '/_post/' + str(post.pk) if os.path.exists(filename): f = open(filename, 'rb') content = f.read().decode('utf-8') f.close() else: content = 'Empty post' comments = Comment.objects.filter(post=post).order_by('date') comment_list = [comment for comment in comments] return render(request, 'edit_post.html', { 'form': form, 'post_id' : post_id, 'content' : content, 'blog_id' : blog_id, 'comments' : comment_list, 'all_tags' : Tag.objects.all().order_by('name'), 'editor' : post.get_editor() }) @login_required def edit_draft(request, draft_id): (b, draft) = have_I_right(request, None, draft_id, cls=Draft) title = draft.title blog_id = b.id if request.method == 'POST': if 'edit' in request.POST: content_format = Post.CONTENT_HTML if request.POST['editor'] == 'text': content_format = Post.CONTENT_TEXT draft.content_format = content_format form = DraftForm(request.POST, instance=draft) if form.is_valid(): if title != request.POST['title']: draft.remove() form.save() draft.createDraft(request.POST['content'], request.POST['text_tags']) return HttpResponseRedirect('/blog/' + str(blog_id)) elif 'post' in request.POST: content_format = Post.CONTENT_HTML if request.POST['editor'] == 'text': content_format = Post.CONTENT_TEXT post = Post(blog=Blog.objects.get(pk=blog_id), author=User.objects.get(pk=request.user.id), creation_date=datetime.now(), modification_date=datetime.now(), content_format=content_format) content = request.POST['content'] # del request.POST['content'] form = PostForm(request.POST, instance=post) if form.is_valid(): draft.delete() form = form.save() form.createPost(content, request.POST['text_tags']) s = Search() s.index_post(b, form.id) request.session['cur_page'] = 0 return HttpResponseRedirect('/blog/' + str(blog_id)) else: if 'cancel' in request.POST: return HttpResponseRedirect('/blog/' + str(blog_id)) else: form = PostForm(instance=draft, initial={'text_tags':', '.join((tag.name) for tag in draft.tags.all().order_by('name'))}) filename = b.src_path + '/_draft/' + str(draft.pk) if os.path.exists(filename): f = open(filename, 'rb') content = f.read().decode('utf-8') f.close() else: content = 'Empty draft' return render(request, 'edit_draft.html', { 'form': form, 'draft_id' : draft_id, 'content' : content, 'blog_id' : blog_id, 'all_tags' : Tag.objects.all().order_by('name'), 'editor' : draft.get_editor() }) @login_required def delete_post(request, post_id): (b, post) = have_I_right(request, None, post_id) s = Search() s.delete_post(b, post_id) post.delete() return HttpResponseRedirect('/blog/' + str(b.id)) @login_required def delete_draft(request, draft_id): (b, draft) = have_I_right(request, None, draft_id, cls=Draft) draft.delete() return HttpResponseRedirect('/blog/' + str(b.id)) def _generate(request, blog_id, report): b,_ = have_I_right(request, blog_id) posts = Post.objects.filter(blog=b).order_by('-creation_date') nb_pages = int(len(posts)/50) posts = posts[0:50] b = Blog.objects.get(pk=blog_id) form = BlogForm(instance=b) comments = Comment.objects.all() dict_comments = {} for comment in comments: key = comment.post.id dict_comments[key] = dict_comments.get(key, 0) + 1 navigation_bar = createNavigationBar(b.id, 0, nb_pages) c = {'blog' : b, 'posts' : posts, 'form' : form, 'report': report, 'comments' : dict_comments, 'navigation_bar' : navigation_bar} return render(request, 'generate.html', c) @login_required def generate(request, blog_id): b,_ = have_I_right(request, blog_id) report = b.generate(request) return _generate(request, blog_id, report) @login_required def generate_post(request, blog_id, post_id): b,post = have_I_right(request, blog_id, post_id) report = b.generate_post(request, post) return _generate(request, blog_id, report) @login_required def generate_search(request, blog_id): b,_ = have_I_right(request, blog_id) hash_posts = {} hash_posts_content = {} s = Search(hash_posts, hash_posts_content) report = s.create_index(b) return _generate(request, blog_id, report) @csrf_exempt def search(request, blog_id): from dynastie.generators import search if not 'HTTP_REFERER' in request.META: return HttpResponseForbidden() ref = request.META['HTTP_REFERER'] b = Blog.objects.filter(pk=blog_id) if len(b) == 0: return HttpResponseRedirect(ref) b = b[0] if 'text' in request.POST: text = request.POST['text'] else: return HttpResponseRedirect(ref) s = Search() post_list = s.search(b, text) if post_list is None: post_list = [] hash_posts = {} hash_posts_content = {} s = search.Search(hash_posts, hash_posts_content) res = s.generate(b, b.src_path, b.output_path, post_list) c = {'result' : res} # Simple wrapper to HTML content return render(request, 'search.html', c) @login_required def preview(request, blog_id): from dynastie.generators import post (b, p) = have_I_right(request, blog_id) content = request.POST['content'] if request.POST['editor'] == 'text': from dynastie.generators import markdown2 content = markdown2.markdown(content, extras=['fenced-code-blocks']) values = {'title' : request.POST['title'], \ 'author' : request.user.first_name + ' ' + request.user.last_name, \ 'content' : content } engine = globals()['post'] for name, obj in inspect.getmembers(engine): if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \ and obj.__module__.endswith("post"): e = obj() content = e.preview(request, b.src_path, values) break output = b.output_path path = output + '/preview.html' if os.path.exists(path): os.unlink(path) f = open(path, 'wb') f.write(content.encode('utf-8')) f.close() c = {'content' : content} return HttpResponseRedirect('http://' + b.name + '/preview.html') # return HttpResponseRedirect('http://' + 'localhost:8080' + '/preview.html') def _tinymcelist(request, b, year, month): ret = 'var tinyMCEImageList = new Array(' if month < 10: suffix = '/images/' + str(year) + '/0' + str(month) else: suffix = '/images/' + str(year) + '/' + str(month) path = b.src_path + '/' + suffix url = 'http://' + b.name + suffix + '/' if os.path.exists(path): files = '' for p in os.listdir(path): files += '["' + p + '", "' + url + p + '"],' # Remove last comma if len(files) != 0: ret += files[:-1] ret += ');' return ret @login_required def tinymcelist_add(request, blog_id): now = datetime.now() year = now.year month = now.month try: (b, p) = have_I_right(request, blog_id) except Http404: return HttpResponse('', content_type='application/x-javascript') ret = _tinymcelist(request, b, year, month) return HttpResponse(ret, content_type='application/x-javascript') @login_required def tinymcelist_edit(request, post_id): try: (b, post) = have_I_right(request, None, post_id) except Http404: return HttpResponse('', content_type='application/x-javascript') year = post.creation_date.year month = post.creation_date.month ret = _tinymcelist(request, b, year, month) return HttpResponse(ret, content_type='application/x-javascript') @csrf_exempt def add_comment(request, post_id, parent_id): from dynastie.generators import post if not 'HTTP_REFERER' in request.META: ref = "/" else: ref = request.META['HTTP_REFERER'] # Anti robot !! if not 'email' in request.POST or request.POST['email'] != '': if 'HTTP_X_REAL_IP' in request.META: print('Dynastie : fucking robot %s' % (request.META['HTTP_X_REAL_IP'])) else: print('Dynastie : fucking robot %s' % (request.META['REMOTE_ADDR'])) return HttpResponseRedirect(ref) post = Post.objects.get(pk=post_id) if post is None: return HttpResponseRedirect(ref) blog = Blog.objects.get(pk=post.blog_id) if blog is None: return HttpResponseRedirect(ref) parent_id = int(parent_id) if parent_id != 0: parentComment = Comment.objects.get(pk=parent_id) else: parentComment = None if request.POST['author'] == '' or request.POST['the_comment'] == '': return HttpResponseRedirect(ref) # Behind nginx proxy if 'HTTP_X_FORWARDED_FOR' in request.META: ip = request.META['HTTP_X_FORWARDED_FOR'] else: ip = request.META['REMOTE_ADDR'] # Avoid script injection the_comment = request.POST['the_comment'].strip() the_comment = the_comment.replace('<', '<') the_comment = the_comment.replace('>', '>') the_comment = the_comment.replace('\n', '
') the_comment = re.sub('#([0-9]+)', '#\\1', the_comment) if 'mel' in request.POST: mel = request.POST['mel'].strip() else: mel = '' comment = Comment(post=post, parent=parentComment, date=datetime.now(), author=request.POST['author'].strip(),\ email=mel, the_comment=the_comment, ip=ip) comment.save() engine = globals()['post'] post_list = [post] hash_post = {} hash_post_content = {} for name, obj in inspect.getmembers(engine): if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \ and obj.__module__.endswith("post"): e = obj(hash_post, hash_post_content) content = e._generate(blog, blog.src_path, blog.output_path, post_list) break # Send emails emails = {} comments = Comment.objects.filter(post=post).order_by('date') comment_index = str(len(comments)) for comment in comments: email = comment.email if email != '' and email != request.POST['mel'] and not email in emails: emails[email] = comment.author if post.author.email not in emails: emails[post.author.email] = post.author.first_name if len(emails) > 0: connection = mail.get_connection(fail_silently=True) connection.open() messages = [] subject = '[%s] Nouveau commentaire pour l\'article "%s"' % (blog.name, post.title) for email,author in emails.items(): text_body = u'Bonjour %s,\n\nUn nouveau commentaire a été posté pour l\'article "%s".\n\n' % (author, post.title) text_body += u'Pour le consulter, rendez vous sur http://%s%s#comment_%s\n\n----------------\n\n' % (blog.name, post.getPath(), comment_index) text_body += the_comment text_body += '\n' html_body = u'' html_body += u'Bonjour %s,

Un nouveau commentaire a été posté pour l\'article "%s".

' % (author, post.title) html_body = html_body + u'Pour le consulter, rendez vous sur http://%s%s#comment_%s

----------------
'  % (blog.name, post.getPath(), comment_index, blog.name, post.getPath(), comment_index)
            c = comment.the_comment
            html_body += the_comment + '
' html_body += '' msg = EmailMultiAlternatives(subject, text_body, 'no-reply@%s' % blog.name , [email]) msg.attach_alternative(html_body, "text/html") messages.append(msg) connection.send_messages(messages) connection.close() ref = ref + '#comment_%s' % (comment_index) response = HttpResponseRedirect(ref) response['Cache-Control'] = 'no-store, no-cache, must-revalidate' response['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT' # This cause problems with non-ascii characters, disabled until Python 3. # response.set_cookie('author', to_unicode(request.POST['author']), domain=blog.name, secure=True, httponly=False); # if mel != '': # response.set_cookie('email', mel, 'utf-8', domain=blog.name, secure=True, httponly=False); return response @login_required def edit_comment(request, comment_id): comment = Comment.objects.get(pk=comment_id) if comment is None: return Http404 (b, post) = have_I_right(request, None, comment.post_id) post_id = comment.post_id if request.method == 'POST': if 'edit' in request.POST: form = CommentForm(request.POST, instance=comment) if form.is_valid(): form = form.save() return HttpResponseRedirect('/post/edit/' + str(post_id)) else: return HttpResponseRedirect('/post/edit/' + str(post_id)) else: comment._remove_br() form = CommentForm(instance=comment) return render(request, 'edit_comment.html', {'form': form, 'comment':comment}) @login_required def delete_comment(request, comment_id): comment = Comment.objects.get(pk=comment_id) if comment is None: return Http404 (b, post) = have_I_right(request, None, comment.post_id) post_id = comment.post_id childs = Comment.objects.filter(parent=comment.id) try: parent = comment.parent except: parent = None for child in childs: child.parent = parent child.save() comment.delete() return HttpResponseRedirect('/post/edit/' + str(post_id))