Commit af0b2a6c by Bridger Maxwell

Merge branch 'edx_release'

Conflicts:
	wiki/decorators.py
	wiki/views/article.py
parents 489dcba8 82806fa6
...@@ -102,12 +102,15 @@ def get_article(func=None, can_read=True, can_write=False, ...@@ -102,12 +102,15 @@ def get_article(func=None, can_read=True, can_write=False,
else: else:
raise TypeError('You should specify either article_id or path') raise TypeError('You should specify either article_id or path')
# If the article has been deleted, show a special page. if not deleted_contents:
if not deleted_contents and article.current_revision and article.current_revision.deleted: # If the article has been deleted, show a special page.
if urlpath: 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: 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: if article.current_revision.locked and not_locked:
return response_forbidden(request, article, urlpath) return response_forbidden(request, article, urlpath)
......
...@@ -74,6 +74,18 @@ class URLPath(MPTTModel): ...@@ -74,6 +74,18 @@ class URLPath(MPTTModel):
return "/".join(slugs) + "/" 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 @classmethod
def root(cls): def root(cls):
site = Site.objects.get_current() site = Site.objects.get_current()
......
...@@ -7,11 +7,12 @@ from django_notify import notify ...@@ -7,11 +7,12 @@ from django_notify import notify
from django_notify.models import Subscription from django_notify.models import Subscription
from wiki import models as wiki_models from wiki import models as wiki_models
from wiki.models.pluginbase import ArticlePlugin
from wiki.core.plugins import registry from wiki.core.plugins import registry
from wiki.plugins.notifications import ARTICLE_EDIT #TODO: Is this bad practice? from wiki.plugins.notifications import ARTICLE_EDIT #TODO: Is this bad practice?
from wiki.plugins.notifications import settings from wiki.plugins.notifications import settings
class ArticleSubscription(wiki_models.pluginbase.ArticlePlugin, Subscription): class ArticleSubscription(ArticlePlugin, Subscription):
def __unicode__(self): def __unicode__(self):
return (_(u"%(user)s subscribing to %(article)s (%(type)s)") % return (_(u"%(user)s subscribing to %(article)s (%(type)s)") %
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<div class="span6"> <div class="span6">
<div class="well"> <div class="well">
<h2>{% trans "Restore" %}</h2> <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> <p>
<a href="?restore=1" class="btn"> <a href="?restore=1" class="btn">
<span class="icon-repeat"></span> <span class="icon-repeat"></span>
......
...@@ -130,8 +130,10 @@ class Delete(FormView, ArticleMixin): ...@@ -130,8 +130,10 @@ class Delete(FormView, ArticleMixin):
if urlpath and urlpath.parent: if urlpath and urlpath.parent:
self.next = reverse('wiki:get', kwargs={'path': urlpath.parent.path}) self.next = reverse('wiki:get', kwargs={'path': urlpath.parent.path})
elif urlpath: elif urlpath:
# We are a urlpath with no parent. This is the root
self.cannot_delete_root = True self.cannot_delete_root = True
else: else:
# We have no urlpath. Get it if a urlpath exists
for art_obj in article.articleforobject_set.filter(is_mptt=True): for art_obj in article.articleforobject_set.filter(is_mptt=True):
if art_obj.content_object.parent: if art_obj.content_object.parent:
self.next = reverse('wiki:get', kwargs={'article_id': art_obj.content_object.parent.article.id}) self.next = reverse('wiki:get', kwargs={'article_id': art_obj.content_object.parent.article.id})
...@@ -156,39 +158,32 @@ class Delete(FormView, ArticleMixin): ...@@ -156,39 +158,32 @@ class Delete(FormView, ArticleMixin):
return kwargs return kwargs
@disable_notify @disable_notify
def delete_children(self, purge=False, restore=False): def delete_children(self, purge=False):
assert not (restore and purge), "You cannot purge a restore"
if purge: if purge:
for child in self.article.get_children(articles__article__current_revision__deleted=False): for child in self.article.get_children(articles__article__current_revision__deleted=False):
child.delete() child.delete()
else: # If it is not a purge there is no need to delete the children. Having a deleted parent is enough
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): def form_valid(self, form):
cd = form.cleaned_data cd = form.cleaned_data
purge = cd['purge']
#If we are purging, only moderators can delete articles with children
cannot_delete_children = False cannot_delete_children = False
can_moderate = self.article.can_moderate(self.request.user) 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 cannot_delete_children = True
if self.cannot_delete_root or cannot_delete_children: 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.')) 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) return redirect('wiki:get', article_id=self.article.id)
# First, remove children
self.delete_children(purge=cd['purge']) if can_moderate and purge:
# First, remove children
if can_moderate and cd['purge']: self.delete_children(purge=purge)
self.article.delete() self.article.delete()
messages.success(self.request, _(u'This article together with all its contents are now completely gone! Thanks!')) messages.success(self.request, _(u'This article together with all its contents are now completely gone! Thanks!'))
else: else:
...@@ -327,17 +322,24 @@ class Deleted(Delete): ...@@ -327,17 +322,24 @@ class Deleted(Delete):
self.urlpath = kwargs.get('urlpath', None) self.urlpath = kwargs.get('urlpath', None)
self.article = article 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) 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) return redirect('wiki:get', article_id=article.id)
# Restore # Restore
if (request.GET.get('restore', False) and if (request.GET.get('restore', False) and
(not article.current_revision.locked and article.can_delete(request.user)) or (not article.current_revision.locked and article.can_delete(request.user)) or
article.can_moderate(request.user)): article.can_moderate(request.user)):
self.delete_children(restore=True)
revision = models.ArticleRevision() revision = models.ArticleRevision()
revision.inherit_predecessor(self.article) revision.inherit_predecessor(self.article)
revision.set_from_request(request) 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