# -*- 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 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 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'] = '' values['content'] = self.pygmentCode(values['content']) self.simpleTransform(v, dom, root, node) content_nodes = root.getElementsByTagName("div") post_transform = ('post_content') 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': new_node = dom.createTextNode(values['content']) content_node.appendChild(new_node) post_nodes = dom.getElementsByTagNameNS(self.URI, "post") post_elem = post_nodes[0] post_elem.parentNode.removeChild(post_elem) return post_elem def preview(self, src, values): from dynastie.models import Blog # 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')