Commit 6be6a0c1 by benjaoming

Merge branch 'master' of github.com:benjaoming/django-wiki

parents 915260d6 32416cd1
......@@ -102,12 +102,15 @@ def get_article(func=None, can_read=True, can_write=False,
else:
raise TypeError('You should specify either article_id or path')
# If the article has been deleted, show a special page.
if not deleted_contents and article.current_revision and article.current_revision.deleted:
if not deleted_contents:
# If the article has been deleted, show a special page.
if urlpath:
return redirect('wiki:deleted', path=urlpath.path)
if urlpath.is_deleted(): # This also checks all ancestors
return redirect('wiki:deleted', path=urlpath.path)
else:
return redirect('wiki:deleted', article_id=article.id)
if article.current_revision and article.current_revision.deleted:
return redirect('wiki:deleted', article_id=article.id)
if article.current_revision.locked and not_locked:
return response_forbidden(request, article, urlpath)
......
......@@ -74,6 +74,18 @@ class URLPath(MPTTModel):
return "/".join(slugs) + "/"
def is_deleted(self):
"""
Returns True if this article or any of its ancestors have been deleted
"""
return self.first_deleted_ancestor() is not None
def first_deleted_ancestor(self):
for ancestor in self.cached_ancestors + [self]:
if ancestor.article.current_revision.deleted == True:
return ancestor
return None
@classmethod
def root(cls):
site = Site.objects.get_current()
......@@ -202,39 +214,40 @@ def on_article_relation_save(instance, *args, **kwargs):
post_save.connect(on_article_relation_save, ArticleForObject)
def on_article_delete(instance, *args, **kwargs):
# If an article is deleted, then throw out its URLPaths
# But move all descendants to a lost-and-found node.
site = Site.objects.get_current()
# Get the Lost-and-found path or create a new one
try:
lost_and_found = URLPath.objects.get(slug=settings.LOST_AND_FOUND_SLUG,
parent=URLPath.root(),
site=site)
except URLPath.DoesNotExist:
article = Article(group_read = True,
group_write = False,
other_read = False,
other_write = False)
article.add_revision(ArticleRevision(
content=_(u'Articles who lost their parents\n'
'===============================\n\n'
'The children of this article have had their parents deleted. You should probably find a new home for them.'),
title=_(u"Lost and found")))
lost_and_found = URLPath.objects.create(slug=settings.LOST_AND_FOUND_SLUG,
parent=URLPath.root(),
site=site,
article=article)
article.add_object_relation(lost_and_found)
for urlpath in URLPath.objects.filter(articles__article=instance, site=site):
# Delete the children
for child in urlpath.get_children():
child.move_to(lost_and_found)
# ...and finally delete the path itself
# TODO: This should be unnecessary because of URLPath.article(...ondelete=models.CASCADE)
urlpath.delete()
pre_delete.connect(on_article_delete, Article)
# TODO: When a parent all of its children are purged, they get sucked up into the lost and found. It is disabled for now.
# def on_article_delete(instance, *args, **kwargs):
# # If an article is deleted, then throw out its URLPaths
# # But move all descendants to a lost-and-found node.
# site = Site.objects.get_current()
#
# # Get the Lost-and-found path or create a new one
# try:
# lost_and_found = URLPath.objects.get(slug=settings.LOST_AND_FOUND_SLUG,
# parent=URLPath.root(),
# site=site)
# except URLPath.DoesNotExist:
# article = Article(group_read = True,
# group_write = False,
# other_read = False,
# other_write = False)
# article.add_revision(ArticleRevision(
# content=_(u'Articles who lost their parents\n'
# '===============================\n\n'
# 'The children of this article have had their parents deleted. You should probably find a new home for them.'),
# title=_(u"Lost and found")))
# lost_and_found = URLPath.objects.create(slug=settings.LOST_AND_FOUND_SLUG,
# parent=URLPath.root(),
# site=site,
# article=article)
# article.add_object_relation(lost_and_found)
#
#
# for urlpath in URLPath.objects.filter(articles__article=instance, site=site):
# # Delete the children
# for child in urlpath.get_children():
# child.move_to(lost_and_found)
# # ...and finally delete the path itself
# # TODO: This should be unnecessary because of URLPath.article(...ondelete=models.CASCADE)
# urlpath.delete()
#
# pre_delete.connect(on_article_delete, Article)
......@@ -7,11 +7,12 @@ from django_notify import notify
from django_notify.models import Subscription
from wiki import models as wiki_models
from wiki.models.pluginbase import ArticlePlugin
from wiki.core.plugins import registry
from wiki.plugins.notifications import ARTICLE_EDIT #TODO: Is this bad practice?
from wiki.plugins.notifications import settings
class ArticleSubscription(wiki_models.pluginbase.ArticlePlugin, Subscription):
class ArticleSubscription(ArticlePlugin, Subscription):
def __unicode__(self):
return (_(u"%(user)s subscribing to %(article)s (%(type)s)") %
......
......@@ -23,7 +23,7 @@
<div class="span6">
<div class="well">
<h2>{% trans "Restore" %}</h2>
<p>{% trans "You may restore this article and its children by clicking restore. Note that this restores ALL children." %}</p>
<p>{% trans "You may restore this article and its children by clicking restore." %}</p>
<p>
<a href="?restore=1" class="btn">
<span class="icon-repeat"></span>
......
......@@ -130,8 +130,10 @@ class Delete(FormView, ArticleMixin):
if urlpath and urlpath.parent:
self.next = reverse('wiki:get', kwargs={'path': urlpath.parent.path})
elif urlpath:
# We are a urlpath with no parent. This is the root
self.cannot_delete_root = True
else:
# We have no urlpath. Get it if a urlpath exists
for art_obj in article.articleforobject_set.filter(is_mptt=True):
if art_obj.content_object.parent:
self.next = reverse('wiki:get', kwargs={'article_id': art_obj.content_object.parent.article.id})
......@@ -154,42 +156,31 @@ class Delete(FormView, ArticleMixin):
kwargs['article'] = self.article
kwargs['has_children'] = bool(self.children_slice)
return kwargs
@disable_notify
def delete_children(self, purge=False, restore=False):
assert not (restore and purge), "You cannot purge a restore"
if purge:
for child in self.article.get_children(articles__article__current_revision__deleted=False):
child.delete()
else:
for child in self.article.get_children(articles__article__current_revision__deleted=restore):
revision = models.ArticleRevision()
revision.inherit_predecessor(child.article)
revision.set_from_request(self.request)
if restore:
revision.automatic_log = _(u'Restoring children of "%s"') % self.article.current_revision.title
else:
revision.automatic_log = _(u'Deleting children of "%s"') % self.article.current_revision.title
revision.deleted = not restore
child.article.add_revision(revision)
def form_valid(self, form):
cd = form.cleaned_data
purge = cd['purge']
#If we are purging, only moderators can delete articles with children
cannot_delete_children = False
can_moderate = self.article.can_moderate(self.request.user)
if self.children_slice and not can_moderate:
if purge and self.children_slice and not can_moderate:
cannot_delete_children = True
if self.cannot_delete_root or cannot_delete_children:
messages.error(self.request, _(u'This article cannot be deleted because it has children or is a root article.'))
return redirect('wiki:get', article_id=self.article.id)
# First, remove children
self.delete_children(purge=cd['purge'])
if can_moderate and cd['purge']:
self.article.delete()
if can_moderate and purge:
# First, remove children
if self.urlpath:
for descendant in self.urlpath.get_descendants(include_self=True):
descendant.article.delete()
else:
self.article.delete()
messages.success(self.request, _(u'This article together with all its contents are now completely gone! Thanks!'))
else:
revision = models.ArticleRevision()
......@@ -327,17 +318,24 @@ class Deleted(Delete):
self.urlpath = kwargs.get('urlpath', None)
self.article = article
if not article.current_revision.deleted:
if self.urlpath:
if self.urlpath:
deleted_ancestor = self.urlpath.first_deleted_ancestor()
if deleted_ancestor is None:
# No one is deleted!
return redirect('wiki:get', path=self.urlpath.path)
else:
elif deleted_ancestor != self.urlpath:
# An ancestor was deleted, so redirect to that deleted page
return redirect('wiki:deleted', path=deleted_ancestor.path)
else:
if not article.current_revision.deleted:
return redirect('wiki:get', article_id=article.id)
# Restore
if (request.GET.get('restore', False) and
(not article.current_revision.locked and article.can_delete(request.user)) or
article.can_moderate(request.user)):
self.delete_children(restore=True)
revision = models.ArticleRevision()
revision.inherit_predecessor(self.article)
revision.set_from_request(request)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment