diff --git a/forms.py b/forms.py index 51faa40..21c3d5e 100644 --- a/forms.py +++ b/forms.py @@ -1,4 +1,5 @@ from django.forms import ModelForm +from django import forms from dynastie.models import * class BlogForm(ModelForm): @@ -6,6 +7,10 @@ class BlogForm(ModelForm): model = Blog class PostForm(ModelForm): + description = forms.CharField(widget=forms.Textarea(attrs={'rows':'5', 'cols':'50'}), required=False) + keywords = forms.CharField(widget=forms.Textarea(attrs={'rows':'2', 'cols':'50'}), required=False) + text_tags = forms.CharField(widget=forms.Textarea(attrs={'rows':'2', 'cols':'50'}), required=False) + class Meta: model = Post exclude = ('title_slug', 'creation_date', 'modification_date', 'author', 'blog', 'tags') @@ -28,3 +33,8 @@ class CommentForm(ModelForm): class Meta: model = Comment exclude = ('post', 'parent', 'date') + +class TagForm(ModelForm): + class Meta: + model = Tag + exclude = ('blog', 'name_slug') diff --git a/generators/__init__.py b/generators/__init__.py index bd07e83..db72da4 100644 --- a/generators/__init__.py +++ b/generators/__init__.py @@ -1 +1 @@ -__all__ = ["generator", "index", "post", "category", "archive", "rss", "atom"] +__all__ = ["generator", "index", "post", "category", "tag", "archive", "rss", "atom"] diff --git a/generators/archive.py b/generators/archive.py index 0ffae95..808430f 100644 --- a/generators/archive.py +++ b/generators/archive.py @@ -57,9 +57,10 @@ class Archive(Index): def generate(self, blog, src, output): from dynastie.models import Post, Blog - hooks = {'posts' : self.createPosts, + self.hooks = {'posts' : self.createPosts, 'navigation' : self.createNavigation, - 'archive' : self.createArchive} + 'archive' : self.createArchive, + 'tags' : self.createTags} if not os.path.exists(src + '/_archive.html'): self.addError('No _archive.html found, exiting') @@ -99,7 +100,7 @@ class Archive(Index): if posts[i].creation_date.year != posts[i+1].creation_date.year: dom = parse(src + '/_archive.html') my_post.reverse() - self.createArchives(src, output, dom, hooks, my_post) + self.createArchives(src, output, dom, self.hooks, my_post) self.cur_year = int(posts[i+1].creation_date.year) #print 'New year ' + str(self.cur_year) my_post = [] @@ -114,7 +115,7 @@ class Archive(Index): self.cur_year = int(posts[i].creation_date.year) if len(my_post) != 0: - self.createArchives(src, output, dom, hooks, my_post) + self.createArchives(src, output, dom, self.hooks, my_post) if not self.somethingWrote: self.addReport('Nothing changed') diff --git a/generators/category.py b/generators/category.py index 3c3aff2..28a2f1a 100644 --- a/generators/category.py +++ b/generators/category.py @@ -24,9 +24,10 @@ class Category(Index): def generate(self, blog, src, output): from dynastie.models import Post, Blog, Category - hooks = {'posts' : self.createPosts, + self.hooks = {'posts' : self.createPosts, 'navigation' : self.createNavigation, - 'category' : self.createCategory} + 'category' : self.createCategory, + 'tags' : self.createTags} if not os.path.exists(src + '/_category.html'): self.addError('No _category.html found, exiting') @@ -73,7 +74,7 @@ class Category(Index): while self.cur_page <= self.nb_pages: #print 'Generate ' + filename nodes = dom.getElementsByTagName("*") - nodes[0] = self.parse(src, hooks, posts, dom, nodes[0]) + nodes[0] = self.parse(src, self.hooks, posts, dom, nodes[0]) self.writeIfNotTheSame(output + self.dirname + '/' + filename, nodes[0]) self.cur_page = self.cur_page + 1 filename = self.filename + str(self.cur_page) + '.html' diff --git a/generators/index.py b/generators/index.py index ccdfac1..e74700f 100644 --- a/generators/index.py +++ b/generators/index.py @@ -105,6 +105,9 @@ class Index(DynastieGenerator): post_elem = self.createElement(dom, '', 'No posts yet') posts_elem.appendChild(post_elem) + # Parse inner HTML + self._parse(self.hooks, posts, dom, post_elem) + self.cur_post = self.cur_post + 1 if self.cur_post == len(posts): break @@ -139,12 +142,48 @@ class Index(DynastieGenerator): return recents_elem + def createTags(self, posts, dom, root, node): + from dynastie.models import Post + tags_elem = self.createElement(dom, 'tags') + create_link = (node.getAttribute('link') == '1') + if type(posts) == models.query.QuerySet: + if len(posts) > self.cur_post: + cur_post = posts[self.cur_post] + else: + cur_post = None + elif type(posts) == Post: + cur_post = posts + else: + cur_post = None + + if not cur_post is None: + for tag in cur_post.tags.all(): + if create_link: + tag_elem = self.createElement(dom, 'tag') + link_elem = self.createLinkElem(dom, '/tag/' + tag.name_slug, '#' + tag.name) + tag_elem.appendChild(link_elem) + else: + tag_elem = self.createElement(dom, 'tag', '#' + tag.name) + tags_elem.appendChild(tag_elem) + + if len(cur_post.tags.all()) == 0: + root.removeChild(node) + return None + else: + root.replaceChild(tags_elem, node) + else: + root.removeChild(node) + return None + + return tags_elem + def generate(self, blog, src, output): from dynastie.models import Post, Blog - hooks = {'posts' : self.createPosts, + self.hooks = {'posts' : self.createPosts, 'navigation' : self.createNavigation, - 'recents' : self.createRecents} + 'recents' : self.createRecents, + 'tags' : self.createTags} if not os.path.exists(src + '/_index.html'): self.addError('No _index.html found, exiting') @@ -180,7 +219,7 @@ class Index(DynastieGenerator): while self.cur_page <= self.nb_pages: #print 'Generate ' + filename nodes = dom.getElementsByTagName("*") - nodes[0] = self.parse(src, hooks, posts, dom, nodes[0]) + nodes[0] = self.parse(src, self.hooks, posts, dom, nodes[0]) self.writeIfNotTheSame(output + '/' + filename, nodes[0]) self.cur_page = self.cur_page + 1 filename = 'index' + str(self.cur_page) + '.html' diff --git a/generators/post.py b/generators/post.py index 5d39d79..54102c6 100644 --- a/generators/post.py +++ b/generators/post.py @@ -138,9 +138,10 @@ class Post(Index): def _generate(self, blog, src, output, posts): import xml self.hooks = {'post' : self._createPost, - 'meta' : self.createMetas, - 'comments' : self.createComments, - 'replace' : self.createReplace} + 'meta' : self.createMetas, + 'comments' : self.createComments, + 'replace' : self.createReplace, + 'tags' : self.createTags} if not os.path.exists(src + '/_post.html'): self.addError('No _post.html found, exiting') @@ -210,7 +211,8 @@ class Post(Index): def preview(self, src, values): from dynastie.models import Blog - self.hooks = {'post' : self.createPreview} + self.hooks = {'post' : self.createPreview, + 'tags' : self.createTags} if not os.path.exists(src + '/_post.html'): self.addError('No _post.html found, exiting') diff --git a/models.py b/models.py index 6e067c1..4e6cdd0 100644 --- a/models.py +++ b/models.py @@ -12,6 +12,15 @@ from django.db.models.signals import post_init, post_delete, post_save from django.dispatch import receiver from dynastie.generators import * +def slugify(name): + name = name.strip() + name = normalize('NFKD', name).encode('ascii', 'ignore').replace(' ', '-').lower() + #remove `other` characters + name = sub('[^a-zA-Z0-9_-]', '', name) + #nomalize dashes + name = sub('-+', '-', name) + return name + class Blog(models.Model): name = models.CharField(max_length=255, unique=True) title = models.CharField(max_length=255) @@ -61,7 +70,10 @@ class Blog(models.Model): self.engines.append(globals()['post']) self.engines.append(globals()['index']) self.engines.append(globals()['category']) + self.engines.append(globals()['tag']) self.engines.append(globals()['archive']) + self.engines.append(globals()['atom']) + self.engines.append(globals()['rss']) def copytree(self, src, dst): names = os.listdir(src) @@ -161,29 +173,34 @@ class Category(models.Model): description = models.TextField(max_length=255, blank=True) blog = models.ForeignKey(Blog) - def slugify(self): - name = normalize('NFKD', self.name).encode('ascii', 'ignore').replace(' ', '-').lower() - #remove `other` characters - name = sub('[^a-zA-Z0-9_-]', '', name) - #nomalize dashes - name = sub('-+', '-', name) - self.name_slug = name - def save(self): - self.slugify() + self.name_slug = slugify(self.name) super(Category, self).save() def remove(self, blog): blog.create_paths() output = blog.output_path + '/category/' + self.name_slug - shutil.rmtree(output) + if os.path.exists(output): + shutil.rmtree(output) class Tag(models.Model): name = models.CharField(max_length=255, unique=True) + name_slug = models.CharField(max_length=255) blog = models.ForeignKey(Blog) + def save(self): + self.name_slug = slugify(self.name) + super(Tag, self).save() + + def remove(self, blog): + blog.create_paths() + + output = blog.output_path + '/tag/' + self.name_slug + if os.path.exists(output): + shutil.rmtree(output) + class Post(models.Model): title = models.CharField(max_length=255) title_slug = models.CharField(max_length=255) @@ -204,19 +221,12 @@ class Post(models.Model): filename = filename + self.title_slug + '.html' return filename - 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() + self.title = self.title.strip() + self.title_slug = slugify(self.title) super(Post, self).save() - def createPost(self, content): + def createPost(self, content, tags): b = self.blog b.create_paths() output = b.src_path @@ -224,12 +234,75 @@ class Post(models.Model): os.mkdir(output + '/_post') filename = output + '/_post/' + str(self.pk) - if os.path.exists(filename): - os.unlink(filename) - f = open(filename, 'wb') content = unicode(content) - f.write(content.encode('utf-8')) - f.close() + content = content.encode('utf-8') + modif = True + + if os.path.exists(filename): + f = open(filename, 'rb') + src_md5 = hashlib.md5() + src_md5.update(f.read()) + f.close() + + dst_md5 = hashlib.md5() + dst_md5.update(content) + + if src_md5.digest() == dst_md5.digest(): + modif = False + else: + os.unlink(filename) + + if modif: + f = open(filename, 'wb') + f.write(content) + f.close() + self.modification_date=datetime.now() + + tags_list = Tag.objects.filter(blog_id=self.blog.id) + my_tags = [] + # Create new tags + for tag in tags.split(','): + tag_slug = slugify(tag) + found = False + for t in tags_list: + if t.name_slug == tag_slug: + found = True + break + if not found and not tag in my_tags: + t = Tag(blog=self.blog, name=tag.strip(), name_slug=tag_slug) + t.save() + # print 'Create ' + tag_slug + my_tags.append(tag) + + # Add new tags + post_tags_list = Tag.objects.filter(post=self.id) + for tag in tags.split(','): + tag_slug = slugify(tag) + found = False + for t in post_tags_list: + if t.name_slug == tag_slug: + found = True + break + if not found: + for t in tags_list: + if t.name_slug == tag_slug: + self.tags.add(t) + # print 'Add ' + tag_slug + break + + # Remove old tags + for t in post_tags_list: + found = False + for tag in tags.split(','): + tag_slug = slugify(tag) + if t.name_slug == tag_slug: + found = True + break + if not found: + # print 'Remove ' + t.name_slug + self.tags.remove(t) + + self.save() def remove(self): b = self.blog @@ -267,7 +340,7 @@ class Comment(models.Model): ip = models.GenericIPAddressField() @receiver(post_init, sender=Blog) -def delete_blog_signal(sender, **kwargs): +def init_blog_signal(sender, **kwargs): kwargs['instance'].create_paths() @receiver(post_delete, sender=Blog) diff --git a/sites/blog.soutade.fr/_archive.html b/sites/blog.soutade.fr/_archive.html index 5ca1e8d..ef6a34f 100755 --- a/sites/blog.soutade.fr/_archive.html +++ b/sites/blog.soutade.fr/_archive.html @@ -6,6 +6,7 @@
|
Écrit par
+ diff --git a/sites/blog.soutade.fr/_category.html b/sites/blog.soutade.fr/_category.html index 575ceb4..2e55c40 100755 --- a/sites/blog.soutade.fr/_category.html +++ b/sites/blog.soutade.fr/_category.html @@ -6,6 +6,7 @@
|
Écrit par
+ diff --git a/sites/blog.soutade.fr/_index.html b/sites/blog.soutade.fr/_index.html index 468d17c..ffda613 100755 --- a/sites/blog.soutade.fr/_index.html +++ b/sites/blog.soutade.fr/_index.html @@ -5,6 +5,7 @@
|
Écrit par
+ diff --git a/sites/blog.soutade.fr/_post.html b/sites/blog.soutade.fr/_post.html index e8b8231..c4ecde6 100755 --- a/sites/blog.soutade.fr/_post.html +++ b/sites/blog.soutade.fr/_post.html @@ -6,6 +6,7 @@
|
Écrit par
+ diff --git a/sites/blog.soutade.fr/_tag.html b/sites/blog.soutade.fr/_tag.html new file mode 100644 index 0000000..7ab0a6d --- /dev/null +++ b/sites/blog.soutade.fr/_tag.html @@ -0,0 +1,14 @@ + +
+ +
+ +
+ |
Écrit par
+
+ +
+ +
+ +
diff --git a/sites/blog.soutade.fr/css/blog.css b/sites/blog.soutade.fr/css/blog.css index 8648de7..5fa0111 100755 --- a/sites/blog.soutade.fr/css/blog.css +++ b/sites/blog.soutade.fr/css/blog.css @@ -257,7 +257,7 @@ div.recents margin-left:20px; } -#archive_year, #category_name +#archive_year, #category_name, #tag_name { font-size:50; padding-bottom:20px; @@ -363,4 +363,14 @@ ul li { display:none; padding:5px; +} + +.tags, .tag +{ + display:inline; +} + +.tag +{ + margin-left:10px; } \ No newline at end of file diff --git a/static/js/dynastie.js b/static/js/dynastie.js index 29e61fc..34891f1 100644 --- a/static/js/dynastie.js +++ b/static/js/dynastie.js @@ -25,12 +25,7 @@ tinyMCE.init({ }); -// From http://planetozh.com/blog/2008/04/javascript-basename-and-dirname/ -function basename(path) { - return path.replace(/\\/g,'/').replace( /.*\//, '' ); -} - -function previewPost() +function previewPost(blog_id) { var w = (screen.width * 80)/100; var h = (screen.height * 80)/100; @@ -39,7 +34,6 @@ function previewPost() var form = document.getElementById("previewForm"); var action = form.action; var target = form.target; - var blog_id = basename(action); form.action="/preview/" + blog_id; form.target="PreviewPost"; diff --git a/templates/add_post.html b/templates/add_post.html index 3287865..3ce151d 100644 --- a/templates/add_post.html +++ b/templates/add_post.html @@ -12,6 +12,6 @@
{% csrf_token %} {{ form.as_p }}

- +
{% endblock %} diff --git a/templates/category.html b/templates/category.html index c851876..6b16ca0 100644 --- a/templates/category.html +++ b/templates/category.html @@ -1,7 +1,6 @@ {% extends "templates/base.html" %} {% block content %} - {% if categories|length == 0 %} Any category available

{% else %} @@ -12,5 +11,4 @@
{% endif %}
  • Add a category
  • - {% endblock %} diff --git a/templates/edit_post.html b/templates/edit_post.html index 7fe89ee..227688e 100644 --- a/templates/edit_post.html +++ b/templates/edit_post.html @@ -12,7 +12,7 @@
    {% csrf_token %} {{ form.as_p }} - +
    {% for comment in comments %} diff --git a/templates/edit_tag.html b/templates/edit_tag.html new file mode 100644 index 0000000..f372a2e --- /dev/null +++ b/templates/edit_tag.html @@ -0,0 +1,9 @@ +{% extends "templates/base.html" %} + +{% block content %} +
    +{% csrf_token %} +{{ form.as_p }} + +
    +{% endblock %} diff --git a/templates/generate.html b/templates/generate.html index dbd51d9..2cebed7 100644 --- a/templates/generate.html +++ b/templates/generate.html @@ -1,7 +1,7 @@ {% extends "templates/base.html" %} {% block content %} -Categories +Home Categories Tags {% if user.is_superuser %}
    {% csrf_token %} diff --git a/templates/tag.html b/templates/tag.html new file mode 100644 index 0000000..5e11577 --- /dev/null +++ b/templates/tag.html @@ -0,0 +1,13 @@ +{% extends "templates/base.html" %} + +{% block content %} +{% if tags|length == 0 %} +Any tag available

    +{% else %} + +{% for tag in tags %} + +{% endfor %} +
    {{ tag.id }}{{ tag.name }}EditDelete
    +{% endif %} +{% endblock %} diff --git a/templates/view_blog.html b/templates/view_blog.html index 38c6f43..b5d2acf 100644 --- a/templates/view_blog.html +++ b/templates/view_blog.html @@ -1,7 +1,7 @@ {% extends "templates/base.html" %} {% block content %} -Categories +Home Categories Tags {% if user.is_superuser %} {% csrf_token %} diff --git a/urls.py b/urls.py index 2ef1d75..7883b20 100644 --- a/urls.py +++ b/urls.py @@ -31,6 +31,9 @@ urlpatterns = patterns('', url(r'^comment/add/(\d+)/(\d+)$', 'dynastie.views.add_comment', name='add_comment'), url(r'^comment/edit/(\d+)$', 'dynastie.views.edit_comment', name='edit_comment'), url(r'^comment/delete/(\d+)$','dynastie.views.delete_comment',name='delete_comment'), + url(r'^tag/(\d+)$', 'dynastie.views.tag', name='tag'), + url(r'^tag/edit/(\d+)$', 'dynastie.views.edit_tag', name='edit_tag'), + url(r'^tag/delete/(\d+)$', 'dynastie.views.delete_tag', name='delete_tag'), # url(r'^dynastie/', include('dynastie.foo.urls')), # Uncomment the admin/doc line below to enable admin documentation: diff --git a/views.py b/views.py index 0637aa8..fa3dd77 100644 --- a/views.py +++ b/views.py @@ -43,12 +43,12 @@ def have_I_right(request, blog_id=None, post_id=None, must_be_superuser=False): if not blog_id is None: if not request.user.is_superuser: - b = Blog.objects.filter(pk=blog_id).filter(writers=request.user.id) + b = Blog.objects.filter(pk=blog_id, writers=request.user.id) if len(b) == 0: raise Http404 b = b[0] else: - b = Blog.objects.get(pk=post.blog.id) + b = Blog.objects.get(pk=blog_id) if b is None: raise Http404 @@ -194,6 +194,7 @@ def edit_category(request, category_id): return HttpResponseRedirect('/category' + str(b.id)) if 'edit' in request.POST: name = category.name + name = name.strip() form = CategoryForm(request.POST, instance=category) # A form bound to the POST data if form.is_valid(): # All validation rules pass if request.POST['name'] != name: @@ -221,6 +222,57 @@ def delete_category(request, category_id): 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} + + return render(request, 'templates/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)[0] + + if request.method == 'POST': # If the form has been submitted... + if 'cancel' in request.POST: + return HttpResponseRedirect('/blog/' + str(b.id)) + if 'edit' in request.POST: + name = tag.name + form = TagForm(request.POST, instance=tag) # A form bound to the POST data + if form.is_valid(): # All validation rules pass + if request.POST['name'] != name: + tag.remove() + form.save() + return HttpResponseRedirect('/blog/' + str(b.id)) + else: + form = TagForm(instance=tag) # An unbound form + + c = {'tag' : tag, 'form' : form} + + return render(request, 'templates/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)[0] + + tag.remove(b) + tag.delete() + + return HttpResponseRedirect('/blog/' + str(b.id)) + @login_required def blog(request): if request.user.is_superuser: @@ -311,7 +363,7 @@ def edit_blog(request, blog_id): @login_required def add_post(request, blog_id): - (b,) = have_I_right(request, blog_id) + (b,p) = have_I_right(request, blog_id) if request.method == 'POST': # If the form has been submitted... if 'add' in request.POST: @@ -321,7 +373,7 @@ def add_post(request, blog_id): form = PostForm(request.POST, instance=post) # A form bound to the POST data if form.is_valid(): # All validation rules pass form = form.save() - form.createPost(content) + form.createPost(content, request.POST['text_tags']) # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/blog/' + blog_id) # Redirect after POST @@ -344,13 +396,12 @@ def edit_post(request, post_id): if request.method == 'POST': # If the form has been submitted... if 'edit' in request.POST: - post.modification_date = datetime.now() form = PostForm(request.POST, instance=post) # A form bound to the POST data if form.is_valid(): # All validation rules pass if title != request.POST['title']: post.remove() form.save() - post.createPost(request.POST['content']) + post.createPost(request.POST['content'], request.POST['text_tags']) # Process the data in form.cleaned_data # ... return HttpResponseRedirect('/blog/' + str(blog_id)) # Redirect after POST @@ -358,7 +409,7 @@ def edit_post(request, post_id): if 'cancel' in request.POST: return HttpResponseRedirect('/blog/' + str(blog_id)) # Redirect after POST else: - form = PostForm(instance=post) # An unbound form + form = PostForm(instance=post, initial={'text_tags':', '.join((tag.name) for tag in post.tags.all())}) # An unbound form b.create_paths() filename = b.src_path + '/_post/' + str(post.pk) @@ -422,7 +473,7 @@ def preview(request, blog_id): 'content' : request.POST['content'] } - (b, ) = have_I_right(request, blog_id) + (b, p) = have_I_right(request, blog_id) b.create_paths() @@ -482,7 +533,7 @@ def tinymcelist_add(request, blog_id): month = now.month try: - (b, ) = have_I_right(request, blog_id) + (b, p) = have_I_right(request, blog_id) except Http404: return HttpResponse('', content_type='application/x-javascript') @@ -545,8 +596,8 @@ def add_comment(request, post_id, parent_id): the_comment = the_comment.replace('<', '<') the_comment = the_comment.replace('>', '>') - comment = Comment(post=post, parent=parentComment, date=datetime.now(), author=request.POST['author'],\ - email=request.POST['email'], the_comment=the_comment, ip=ip) + comment = Comment(post=post, parent=parentComment, date=datetime.now(), author=request.POST['author'].strip(),\ + email=request.POST['email'].strip(), the_comment=the_comment, ip=ip) comment.save() engine = globals()['post'] diff --git a/wsgi.py b/wsgi.py index 9a4e7c6..ea6038b 100644 --- a/wsgi.py +++ b/wsgi.py @@ -18,7 +18,7 @@ import sys os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dynastie.settings") -dynastie_root = '/home/soutade/dynastie/' +dynastie_root = '/home/soutade/Projets_Perso/dynastie2/dynastie/' if dynastie_root not in sys.path: sys.path.append(dynastie_root) dynastie_root += 'dynastie/'