e0b8f544ff
Fix draft inclusion in preview Enhance cache post content (avoid recomputing md5sum if present) Add generation duration time Add post only generation (for Dev) Remove Draft when it becomes Post Update blog Copyright Update TinyMCE plugins for inclusion Sort tags by name
291 lines
11 KiB
Python
Executable File
291 lines
11 KiB
Python
Executable File
# -*- 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 <http://www.gnu.org/licenses/>.
|
|
"""
|
|
import datetime
|
|
import os
|
|
import xml
|
|
from xml.dom.minidom import parse, parseString
|
|
from dynastie.generators.generator import DynastieGenerator, StrictUTF8Writer
|
|
from dynastie.generators.index import Index
|
|
from django.db import models
|
|
from dynastie.tree import TreeNode
|
|
|
|
class Post(Index):
|
|
|
|
def createReplace(self, post, dom, root, replace_elem):
|
|
if not replace_elem.hasAttribute('div_name'):
|
|
self.addError('No attribute div_name for a replace tag')
|
|
return
|
|
|
|
div_element = replace_elem.cloneNode(True)
|
|
div_element.tagName = replace_elem.getAttribute('div_name')
|
|
div_element.removeAttribute('div_name')
|
|
for key,value in replace_elem.attributes.items():
|
|
if key == 'div_name': continue
|
|
value = value.replace('dyn:post_id', str(post.id))
|
|
if self.cur_comment is None:
|
|
value = value.replace('dyn:comment_index', '0')
|
|
value = value.replace('dyn:comment_id', '0')
|
|
else:
|
|
value = value.replace('dyn:comment_index', str(self.comment_index[self.cur_comment.id]))
|
|
value = value.replace('dyn:comment_id', str(self.cur_comment.id))
|
|
value = value.replace('dyn:blog_id', str(self.blog.id))
|
|
url = post.getPath()
|
|
full_url = post.blog.name + url
|
|
value = value.replace('dyn:post_url', url)
|
|
value = value.replace('dyn:post_full_url', full_url)
|
|
|
|
div_element.setAttribute(key, value)
|
|
|
|
root.replaceChild(div_element, replace_elem)
|
|
return div_element
|
|
|
|
def createComment(self, comment, dom, comment_elem, root):
|
|
values = {}
|
|
values['comment_index'] = str(self.comment_index[comment.id])
|
|
values['comment_author'] = comment.author
|
|
values['comment_date'] = comment.date.strftime('%d %B %Y %H:%m')
|
|
values['comment_content'] = comment.the_comment
|
|
|
|
self.simpleTransform(values, dom, comment_elem, root)
|
|
|
|
def _createComments(self, rootNode, post, dom, root_comment, root):
|
|
self.cur_comment = rootNode.value
|
|
comment_element = self.createElement(dom, 'comment')
|
|
self.createComment(self.cur_comment, dom, comment_element, root)
|
|
root_comment.appendChild(comment_element)
|
|
# Parse inner HTML
|
|
self._parse(self.hooks, post, dom, comment_element)
|
|
|
|
for commentNode in rootNode.childs:
|
|
self._createComments(commentNode, post, dom, comment_element, root)
|
|
|
|
def createComments(self, post, dom, post_elem, root):
|
|
from dynastie.models import Post, Blog, Comment
|
|
|
|
comments = Comment.objects.filter(post=post).order_by('date')
|
|
|
|
self.cur_comment = None
|
|
self.comment_index = {}
|
|
index = 1
|
|
|
|
rootNode = TreeNode('', '')
|
|
for comment in comments:
|
|
self.comment_index[comment.id] = index
|
|
index = index + 1
|
|
tnode = TreeNode(comment.id, comment)
|
|
if comment.parent is None:
|
|
rootNode.addChildNode(tnode)
|
|
else:
|
|
temp = rootNode.find(comment.parent.id)
|
|
if temp is None:
|
|
self.addWarning('Error with comments chain')
|
|
rootNode.addChildNode(tnode)
|
|
else:
|
|
temp.addChildNode(tnode)
|
|
|
|
initial_root_comment = root_comment = self.createElement(dom, 'comments')
|
|
for tnode in rootNode.childs:
|
|
self._createComments(tnode, post, dom, root_comment, root)
|
|
|
|
# Empty tag seems to crap rendering
|
|
if len(rootNode.childs) == 0:
|
|
post_elem.removeChild(root)
|
|
return None
|
|
else:
|
|
post_elem.replaceChild(root_comment, root)
|
|
return root_comment
|
|
|
|
def createMetas(self, post, dom, meta_elem, root):
|
|
name = root.getAttribute('name')
|
|
if name is None:
|
|
self.addError('Missing name attribute in dyn:meta')
|
|
return
|
|
|
|
new_elem = None
|
|
if name == 'keywords':
|
|
value = post.keywords.replace('"', '“')
|
|
new_elem = self.createMeta(dom, name, value)
|
|
elif name == 'title':
|
|
value = post.title.replace('"', '“')
|
|
new_elem = self.createMeta(dom, name, value)
|
|
elif name == 'description':
|
|
value = post.description.replace('"', '“')
|
|
new_elem = self.createMeta(dom, name, value)
|
|
elif name == 'author':
|
|
try:
|
|
new_elem = self.createMeta(dom, name, post.author.first_name + ' ' + post.author.last_name)
|
|
except:
|
|
return None
|
|
|
|
if not new_elem is None:
|
|
root.parentNode.replaceChild(new_elem, root)
|
|
return new_elem
|
|
else:
|
|
self.addError('name attribute \'' + name + '\' unknown for dyn:meta' )
|
|
return None
|
|
|
|
def createPostTitle(self, post, dom, root, node):
|
|
value = post.title.replace('"', '“')
|
|
self.replaceByText(dom, root, node, value)
|
|
return None
|
|
|
|
def _createPost(self, post, dom, post_elem, root):
|
|
self.cur_post_obj = post
|
|
posts = [post]
|
|
self.createPost(posts, dom, post_elem, root)
|
|
|
|
# Post are appended by index. Remove template
|
|
post_nodes = dom.getElementsByTagNameNS(self.URI, 'post')
|
|
post_elem = post_nodes[0]
|
|
post_elem.parentNode.removeChild(post_elem)
|
|
|
|
title_nodes = dom.getElementsByTagName('title')
|
|
|
|
# Set title to be title's post
|
|
for node in title_nodes:
|
|
if node.hasChildNodes():
|
|
node.removeChild(node.childNodes[0])
|
|
node.appendChild(dom.createTextNode(post.title))
|
|
|
|
return node
|
|
|
|
def _generate(self, blog, src, output, posts):
|
|
from dynastie.search import Search
|
|
|
|
self.cur_comment = None
|
|
self.comment_index = {}
|
|
|
|
self.hooks['post'] = self._createPost
|
|
self.hooks['meta'] = self.createMetas
|
|
self.hooks['comments'] = self.createComments
|
|
self.hooks['replace'] = self.createReplace
|
|
self.hooks['post_title'] = self.createPostTitle
|
|
del self.hooks['navigation']
|
|
del self.hooks['recents']
|
|
del self.hooks['posts']
|
|
|
|
dom = self.parseTemplate(blog, src, output, 'post', None, False)
|
|
if dom is None: return self.report
|
|
|
|
impl = xml.dom.getDOMImplementation()
|
|
s = Search()
|
|
for post in posts:
|
|
filename = output + '/post/'
|
|
filename = filename + post.creation_date.strftime("%Y") + '/' + post.creation_date.strftime("%m") + '/'
|
|
if not os.path.exists(filename):
|
|
os.makedirs(filename)
|
|
filename = filename + post.title_slug + '.html'
|
|
|
|
if not post.published:
|
|
if os.path.exists(filename):
|
|
os.unlink(filename)
|
|
os.unlink(filename + '.gz')
|
|
self.addReport('Remove ' + filename)
|
|
s.delete_post(blog, post.id)
|
|
continue
|
|
#print 'Generate ' + filename
|
|
dom_ = impl.createDocument('', 'xml', None)
|
|
dom_.replaceChild(dom.firstChild.cloneNode(True), dom_.firstChild)
|
|
nodes = self.parse(src, self.hooks, post, dom_, dom_.firstChild)
|
|
|
|
self.writeIfNotTheSame(filename, nodes)
|
|
|
|
if not self.somethingWrote:
|
|
self.addReport('Nothing changed')
|
|
|
|
return self.report
|
|
|
|
def generate(self, blog, src, output):
|
|
from dynastie.models import Post, Blog
|
|
|
|
self.blog = blog
|
|
|
|
self.parent_posts = []
|
|
posts = Post.objects.all()
|
|
|
|
return self._generate(blog, src, output, posts)
|
|
|
|
def createPreview(self, values, dom, root, node):
|
|
now = datetime.datetime.now()
|
|
|
|
v = {}
|
|
v['title'] = self.createLinkElem(dom, '/preview.html', values['title'])
|
|
v['author'] = values['author']
|
|
v['date'] = now.strftime("%A, %d %B %Y %H:%m")
|
|
v['post_content'] = ''
|
|
|
|
post_content = self._manageInternalPosts(None, values['content'], self.user)
|
|
post_content = self.pygmentCode(post_content)
|
|
|
|
self.simpleTransform(v, dom, root, node)
|
|
|
|
content_nodes = root.getElementsByTagName("div")
|
|
post_transform = ('post_content')
|
|
content_node = None
|
|
for content_node in content_nodes:
|
|
the_class = content_node.getAttribute('class')
|
|
if not the_class in post_transform:
|
|
continue
|
|
if the_class == 'post_content':
|
|
s = u'<div>' + post_content + u'</div>'
|
|
new_node = parseString(s.encode('utf-8'))
|
|
for n in new_node.childNodes[0].childNodes:
|
|
content_node.appendChild(n)
|
|
break
|
|
|
|
post_nodes = dom.getElementsByTagNameNS(self.URI, "post")
|
|
post_elem = post_nodes[0]
|
|
post_elem.parentNode.removeChild(post_elem)
|
|
|
|
return content_node
|
|
|
|
def preview(self, request, src, values):
|
|
from dynastie.models import Blog
|
|
|
|
self.user = request.user
|
|
|
|
# Override all hooks
|
|
self.hooks = {'post' : self.createPreview,
|
|
'tags' : self.createTags,
|
|
}
|
|
|
|
if not os.path.exists(src + '/_post.html'):
|
|
self.addError('No _post.html found, exiting')
|
|
return self.report
|
|
|
|
try:
|
|
dom = parse(src + '/_post.html')
|
|
except xml.dom.DOMException as e:
|
|
self.addError('Error parsing _post.html : ' + e)
|
|
return self.report
|
|
|
|
post_nodes = dom.getElementsByTagNameNS(self.URI, "posts")
|
|
|
|
if post_nodes is None:
|
|
self.addError('No tag dyn:posts found')
|
|
return self.report
|
|
|
|
nodes = dom.getElementsByTagName("*")
|
|
nodes[0] = self.parse(src, self.hooks, values, dom, nodes[0])
|
|
writer = StrictUTF8Writer()
|
|
nodes[0].writexml(writer)
|
|
|
|
return writer.getvalue().encode('utf-8')
|