# -*- 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 import re 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, root, node): self.cur_post_obj = post posts = [post] post_elem = self.createElement(dom, 'post') post_elem = self.createPost(posts, dom, post_elem, node) # Post are appended by index. Remove template root.replaceChild(post_elem, node) 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 post_elem 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 = '
' + post_content + u'
' new_node = parseString(s) 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 iframe_re = re.compile(r'(') 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) content = writer.getvalue().decode('utf-8') # iframe tag must be like , not optimized ', content) return content