Add article generator

This commit is contained in:
Grégory Soutadé 2012-07-22 10:47:24 +02:00
parent fa07825546
commit be306c6643
11 changed files with 237 additions and 34 deletions

View File

@ -8,7 +8,7 @@ class BlogForm(ModelForm):
class ArticleForm(ModelForm):
class Meta:
model = Article
exclude = ('creation_date', 'author', 'blog', 'tags')
exclude = ('title_slug', 'creation_date', 'author', 'blog', 'tags')
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
@ -23,4 +23,3 @@ class UserForm(ModelForm):
class Meta:
model = User
exclude = ('is_staff', 'is_active', 'last_login', 'last_joined', 'user_permissions', 'groups', 'date_joined')

View File

@ -1 +1 @@
__all__ = ["generator", "index"]
__all__ = ["generator", "index", "article"]

62
generators/article.py Normal file
View File

@ -0,0 +1,62 @@
import os
import datetime
from xml.dom.minidom import parse, parseString
from dynastie.generators.generator import DynastieGenerator
from django.db import models
# TODO : content
class Article(DynastieGenerator):
def createArticle(self, article, dom, article_elem, root):
values = {}
values['title'] = article.title
values['author'] = article.author.first_name
values['date'] = article.creation_date.strftime("%d/%m/%Y")
values['content'] = ''
self.simpleTransform(values, dom, article_elem, root)
def parse(self, article, dom, root):
for node in root.childNodes:
if node.prefix == 'dyn':
if node.localName == 'content':
article_elem = self.createElement(dom, 'article')
self.createArticle(article, dom, article_elem, node)
root.replaceChild(article_elem, node)
continue
if node.hasChildNodes():
self.parse(article, dom, node)
return
def generate(self, blog, src, output):
from dynastie.models import Article, Blog
if not os.path.exists(src + '/_article.html'):
self.addError('No _article.html found, exiting')
return self.report
try:
dom = parse(src + '/_article.html')
except xml.dom.DOMException as e:
self.addError('Error parsing _article.html : ' + e)
return self.report
if not os.path.exists(output + '/articles'):
os.mkdir(output + '/articles')
articles = Article.objects.all()
for article in articles:
#print 'Generate ' + filename
nodes = dom.getElementsByTagName("*")
self.parse(article, dom, nodes[0])
self.writeIfNotTheSame(output + '/articles/' + article.title_slug + '.html', nodes[0].toxml('utf8'))
dom = parse(src + '/_article.html')
if not self.somethingWrote:
self.addReport('Nothing changed')
return self.report

View File

@ -7,9 +7,11 @@ class DynastieGenerator:
URI = "http://indefero.soutade.fr/p/dynastie"
report = ''
somethingWrote = False
def __init__(self):
self.report = ''
self.somethingWrote = False
def addReport(self, string, color=''):
if color != '':
@ -40,10 +42,8 @@ class DynastieGenerator:
dst_md5.update(content)
if src_md5.digest() == dst_md5.digest():
self.addReport(filename + ' regenerated with the same content, skipping...')
filename = filename + '.gz'
if not os.path.exists(filename):
self.addReport(filename + ' was not previously compressed')
f = gzip.open(filename, 'wb')
f.write(content)
f.close()
@ -60,6 +60,8 @@ class DynastieGenerator:
f = gzip.open(filename, 'wb')
f.write(content)
f.close()
self.somethingWrote = True
def createElement(self, dom, name='', content=''):
div = dom.createElement('div')

View File

@ -135,5 +135,8 @@ class Index(DynastieGenerator):
self.cur_page = self.cur_page + 1
filename = output + '/index' + str(self.cur_page) + '.html'
if not self.somethingWrote:
self.addReport('Nothing changed')
return self.report

View File

@ -2,6 +2,8 @@ import os
import shutil
import hashlib
import inspect
from unicodedata import normalize
from re import sub
from datetime import datetime
from django.db import models
from django.contrib.auth.models import User
@ -27,14 +29,16 @@ class Blog(models.Model):
self.output_path = 'sites/' + self.name + '_output'
def create(self):
self.create_paths()
if not os.path.exists('sites'):
os.mkdir('sites')
self.remove()
os.mkdir(self.src_path)
os.mkdir(self.output_path)
if not os.path.exists(self.src_path):
os.mkdir(self.src_path)
if not os.path.exists(self.output_path):
os.mkdir(self.output_path)
def remove(self):
if os.path.exists(self.src_path):
shutil.rmtree(self.src_path)
@ -109,6 +113,7 @@ class Blog(models.Model):
r = e.generate(self, self.src_path, self.output_path)
if not r is None:
self.report = self.report + '<br/>\n' + r
return self.report
class Editor(models.Model):
@ -124,6 +129,7 @@ class Tag(models.Model):
class Article(models.Model):
title = models.CharField(max_length=255)
title_slug = models.CharField(max_length=255)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
published = models.BooleanField()
creation_date = models.DateField()
@ -134,6 +140,51 @@ class Article(models.Model):
tags = models.ManyToManyField(Tag, blank=True, null=True)
blog = models.ForeignKey(Blog)
def slugify(self):
name = normalize('NFKD', self.title).encode('ascii', 'ignore').replace(' ', '-').lower()
#remove `other` characters
name = sub('[^a-zA-Z0-9_-]', '', name)
#nomalize dashes
name = sub('-+', '-', name)
self.title_slug = name
def save(self):
self.slugify()
super(Article, self).save()
def createArticle(self, content):
b = self.blog
b.create_paths()
output = b.src_path
if not os.path.exists(output + '/_articles'):
os.mkdir(output + '/_articles')
filename = output + '/_articles/' + str(self.pk)
if os.path.exists(filename):
os.unlink(filename)
f = open(filename, 'wb')
f.write(content)
f.close()
def remove(self):
b = self.blog
b.create_paths()
output = b.src_path
filename = output + '/_articles/' + str(self.pk)
if os.path.exists(filename):
os.unlink(filename)
output = b.output_path
filename = output + '/articles/' + self.title_slug + '.html'
if os.path.exists(filename):
os.unlink(filename)
filename = filename + '.gz'
if os.path.exists(filename):
os.unlink(filename)
class Comment(models.Model):
article = models.ForeignKey(Article)
parent = models.ForeignKey('Comment')
@ -149,3 +200,7 @@ def delete_blog_signal(sender, **kwargs):
@receiver(post_delete, sender=Blog)
def delete_blog_signal(sender, **kwargs):
sender.remove()
@receiver(post_delete, sender=Article)
def delete_article_signal(sender, **kwargs):
sender.remove()

View File

@ -1,8 +1,35 @@
{% extends "templates/base.html" %}
{% block head %}
<script type="text/javascript" src="/static/js/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
editor_selector : "mceAdvanced",
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,charmap,emotions,iespell,media,advhr",
// theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
width: "100%",
height: "400"
});
</script>
{% endblock %}
{% block content %}
<form action="/article/add/{{ blog_id }}" method="post">{% csrf_token %}
{{ form.as_p }}
<textarea name="content" class="mceAdvanced"></textarea><br/><br/>
<input type="submit" name="add" value="Add" /><input type="submit" name="preview" value="Preview" /><input type="submit" name="cancel" value="Cancel" />
</form>
{% endblock %}

View File

@ -1,6 +1,7 @@
<html>
<head>
<title>Dynastie</title>
{% block head %} {% endblock %}
</head>
<body>
<a href="/user">Users</a> <a href="/blog">Blogs</a> <a href="/category">Categories</a> <a href="/disconnect">Disconnect</a><br/><br/>

View File

@ -1,8 +1,35 @@
{% extends "templates/base.html" %}
{% block head %}
<script type="text/javascript" src="/static/js/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
editor_selector : "mceAdvanced",
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,charmap,emotions,iespell,media,advhr",
// theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
width: "100%",
height: "400"
});
</script>
{% endblock %}
{% block content %}
<form action="/article/edit/{{ article_id }}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="edit" value="Edit" /><input type="submit" name="cancel" value="Cancel" />
<textarea name="content" class="mceAdvanced">{{ content }}</textarea>
<input type="submit" name="edit" value="Edit" /><input type="submit" name="preview" value="Preview" /><input type="submit" name="cancel" value="Cancel" />
</form>
{% endblock %}

View File

@ -1,6 +1,9 @@
{% extends "templates/base.html" %}
{% block content %}
{% if edited %}
<p style="color:green">User successfuly updated</p>
{% endif %}
{% if user.is_superuser or user.id == user_to_edit.id %}
<form action="/user/edit/{{ user_to_edit.id }}" method="post">
{% csrf_token %}

View File

@ -1,3 +1,4 @@
import os
from datetime import datetime, date, time
from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout
@ -23,13 +24,13 @@ def index(request):
c = {'auth_key': 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\
'login_failed' : login_failed}
return render(request, 'templates/login.html', c);
return render(request, 'templates/login.html', c)
def disconnect(request):
logout(request)
c = {'auth_key': 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\
'login_failed' : False}
return render(request, 'templates/login.html', c);
return render(request, 'templates/login.html', c)
@login_required
def user(request):
@ -37,7 +38,7 @@ def user(request):
c = {'users' : users}
return render(request, 'templates/user.html', c);
return render(request, 'templates/user.html', c)
@login_required
def add_user(request):
@ -66,21 +67,24 @@ def add_user(request):
@login_required
def edit_user(request, user_id):
if user_id != request.user.id and not request.user.is_superuser:
return HttpResponseRedirect('/user')
user = User.objects.get(pk=user_id)
if user is None:
raise Http404
edited = False
if request.method == 'POST': # If the form has been submitted...
if int(user_id) != int(request.user.id) and (not request.user.is_superuser):
return HttpResponseRedirect('/user/' + str(user_id))
if 'edit' in request.POST:
form = UserForm(request.POST, instance=user) # A form bound to the POST data
form = UserForm(request.POST, instance=user, initial={'password':''}) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
user.set_password(request.POST['password'])
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()
@ -88,11 +92,11 @@ def edit_user(request, user_id):
if 'cancel' in request.POST:
return HttpResponseRedirect('/user')
else:
form = UserForm(instance=user) # An unbound form
form = UserForm(instance=user, initial={'password':''}) # An unbound form
c = {'user_to_edit' : user, 'form' : form, 'edited' : edited}
c = {'user_to_edit' : user, 'form' : form}
return render(request, 'templates/edit_user.html', c);
return render(request, 'templates/edit_user.html', c)
@login_required
def category(request):
@ -100,7 +104,7 @@ def category(request):
c = {'categories' : categories}
return render(request, 'templates/category.html', c);
return render(request, 'templates/category.html', c)
@login_required
def add_category(request):
@ -143,7 +147,7 @@ def edit_category(request, category_id):
c = {'category' : category, 'form' : form}
return render(request, 'templates/edit_category.html', c);
return render(request, 'templates/edit_category.html', c)
@login_required
def delete_category(request, category_id):
@ -168,7 +172,7 @@ def blog(request):
c = {'blogs' : b}
return render(request, 'templates/blog.html', c);
return render(request, 'templates/blog.html', c)
@login_required
def add_blog(request):
@ -207,7 +211,7 @@ def view_blog(request, blog_id):
c = {'blog' : b, 'articles' : articles, 'form' : form}
return render(request, 'templates/view_blog.html', c);
return render(request, 'templates/view_blog.html', c)
@login_required
def edit_blog(request, blog_id):
@ -236,12 +240,12 @@ def edit_blog(request, blog_id):
c = {'blog' : b, 'articles' : articles, 'form' : form}
return render(request, 'templates/view_blog.html', c);
return render(request, 'templates/view_blog.html', c)
@login_required
def add_article(request, blog_id):
if not request.user.is_superuser:
b = Blog.objects.filter(id=blog_id).filter(writers=request.user.id)
b = Blog.objects.filter(id=blog_id).filter(writers=request.user.id)[0]
if b is None:
raise Http404
@ -249,9 +253,12 @@ def add_article(request, blog_id):
if request.method == 'POST': # If the form has been submitted...
if 'add' in request.POST:
article = Article(blog=Blog.objects.get(pk=blog_id), author=User.objects.get(pk=request.user.id), creation_date=datetime.now())
content = request.POST['content']
# del request.POST['content']
form = ArticleForm(request.POST, instance=article) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
form.save()
form = form.save()
form.createArticle(content)
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/blog/' + blog_id) # Redirect after POST
@ -271,18 +278,24 @@ def edit_article(request, article_id):
if article is None:
raise Http404
title = article.title
blog_id = article.blog.id
if not request.user.is_superuser:
b = Blog.objects.filter(id=article.blog.id).filter(writers=request.user.id)
b = Blog.objects.filter(pk=article.blog.id).filter(writers=request.user.id)[0]
if b is None:
raise Http404
else:
b = Blog.objects.get(pk=article.blog.id)
if request.method == 'POST': # If the form has been submitted...
if 'edit' in request.POST:
form = ArticleForm(request.POST, instance=article) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
if title != article.title:
article.remove()
form.save()
# Process the data in form.cleaned_data
# ...
@ -293,8 +306,17 @@ def edit_article(request, article_id):
else:
form = ArticleForm(instance=article) # An unbound form
b.create_paths()
filename = b.src_path + '/_articles/' + str(article.pk)
if os.path.exists(filename):
f = open(filename, 'rb')
content = f.read()
f.close()
else:
content = 'Empty article'
return render(request, 'edit_article.html', {
'form': form, 'article_id' : article_id
'form': form, 'article_id' : article_id, 'content' : content
})
@login_required
@ -304,14 +326,16 @@ def delete_article(request, article_id):
if article is None:
raise Http404
b = Blog.objects.filter(writers=request.user.id).filter(pk=article.blog.id)
b = Blog.objects.filter(writers=request.user.id).filter(pk=article.blog.pk)
if b is None:
raise Http404
blog_id = article.blog.pk
article.delete()
return HttpResponseRedirect('/blog/' + str(article.blog.id))
return HttpResponseRedirect('/blog/' + str(blog_id))
@login_required
def generate(request, blog_id):