# -*- 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 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) orig_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(orig_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) orig_posts = orig_posts.order_by('-creation_date')[start:end] # Select post without drafts if drafts: drafts_id = [draft.id for draft in drafts] posts = [p for p in orig_posts if not p.id in drafts_id] else: posts = orig_posts 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() 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() 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 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) 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 ref = request.META['HTTP_REFERER'] # Anti robot !! if 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))