Skip to content
This repository has been archived by the owner on Feb 1, 2019. It is now read-only.

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
filwaitman committed Jan 9, 2018
1 parent c9a1a75 commit 4269e07
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 824 deletions.
200 changes: 200 additions & 0 deletions aldryn_reversion/admin.py
Expand Up @@ -2,21 +2,44 @@
from __future__ import unicode_literals

from cms.admin.placeholderadmin import PlaceholderAdminMixin
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse, NoReverseMatch
from django.contrib import messages
try:
from django.contrib.admin.utils import unquote
except ImportError:
# Django<=1.6
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
from django.contrib.admin.util import unquote
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
from django.db import transaction
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _

from reversion import VERSION as REVERSION_VERSION
from reversion.admin import VersionAdmin
from reversion.models import Version

from .forms import RecoverObjectWithTranslationForm
from .utils import (
build_obj_repr,
object_is_translation,
get_translation_info_message,
get_conflict_fks_versions,
RecursiveRevisionConflictResolver
)

REVERSION_1_9_OR_HIGHER = REVERSION_VERSION >= (1, 9)


class VersionedPlaceholderAdminMixin(PlaceholderAdminMixin, VersionAdmin):
revision_confirmation_template = 'aldryn_reversion/confirm_reversion.html'
recover_confirmation_template = 'aldryn_reversion/confirm_recover.html'

def log_addition(self, request, obj, change_message=None):
"""
Override reversion.VersionAdmin log addition to provide useful message.
Expand Down Expand Up @@ -83,3 +106,180 @@ def log_deletion(self, request, obj, object_repr):
'object_repr': build_obj_repr(obj.master),
'lang_code': obj.language_code.upper()}
self.log_change(request, obj.master, message, deletion=True)

@transaction.atomic
def revision_view(self, request, object_id, version_id,
extra_context=None):
if not self.has_change_permission(request):
raise PermissionDenied()

obj = get_object_or_404(self.model, pk=unquote(object_id))
version = get_object_or_404(Version, pk=unquote(version_id),
object_id=force_text(obj.pk))
revision = version.revision

if request.method == "POST":
revision.revert()

opts = self.model._meta
pk_value = obj._get_pk_val()
preserved_filters = self.get_preserved_filters(request)

msg_dict = {
'name': force_text(opts.verbose_name),
'obj': force_text(obj)
}
msg = _('The %(name)s "%(obj)s" was successfully reverted. '
'You may edit it again below.') % msg_dict
self.message_user(request, msg, messages.SUCCESS)
redirect_url = reverse(
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
args=(pk_value,),
current_app=self.admin_site.name
)
redirect_url = add_preserved_filters({
'preserved_filters': preserved_filters,
'opts': opts,
}, redirect_url)
return HttpResponseRedirect(redirect_url)
else:
context = {
'object': obj,
'version': version,
'revision': revision,
'revision_date': revision.date_created,
'versions': revision.version_set.order_by(
'content_type__model', 'object_id_int').all,
'object_name': force_text(self.model._meta.verbose_name),
'app_label': self.model._meta.app_label,
'opts': self.model._meta,
'add': False,
'change': True,
'save_as': False,
'has_add_permission': self.has_add_permission(request),
'has_change_permission': self.has_change_permission(
request, obj),
'has_delete_permission': self.has_delete_permission(
request, obj),
'has_file_field': True,
'has_absolute_url': False,
'original': obj,
}
return render(request, self.revision_confirmation_template, context)

@transaction.atomic
def recover_view(self, request, version_id, extra_context=None):
if not self.has_change_permission(request):
raise PermissionDenied()

version = get_object_or_404(Version, pk=unquote(version_id))
obj = version.object_version.object
revision = version.revision

# check for conflicts, it is better that user would solve them
conflict_fks_versions = get_conflict_fks_versions(
obj, version, revision)

# build urls to point user onto restore links for conflicts
opts = self.model._meta
non_reversible_by_user = []
conflicts_links_to_restore = []
for fk_version in conflict_fks_versions:
# try to point user to conflict recover views
try:
link = reverse(
'admin:{0}_{1}_recover'.format(
opts.app_label,
fk_version.object_version.object._meta.model_name),
args=[fk_version.pk])
link_dict = {
'version': fk_version,
'link': link
}
except NoReverseMatch:
# if there is exception either model is not registered
# with VersionedPlaceholderAdminMixin or there is no admin
# for that model. In both cases we need to revert this object
# to avoid conflicts / integrity errors
non_reversible_by_user.append(fk_version)
else:
conflicts_links_to_restore.append(link_dict)

# if there are conflicts that cannot be resolved manually by the user
# rely on resolver.
if len(non_reversible_by_user) > 0:
non_reversible_by_user = RecursiveRevisionConflictResolver(
non_reversible_by_user[0], non_reversible_by_user[1:]).resolve()

# prepare form kwargs
restore_form_kwargs = {
'revision': revision,
'obj': obj,
'version': version,
'resolve_conflicts': non_reversible_by_user,
}

if request.method == "POST":
form = RecoverObjectWithTranslationForm(request.POST,
**restore_form_kwargs)
# form.is_valid would perform validation against foreign keys
if form.is_valid():
# form save will restore desired versions for object and its
# translations
form.save()
# FIXME: optimize response
opts = self.model._meta
pk_value = obj._get_pk_val()
preserved_filters = self.get_preserved_filters(request)

msg_dict = {
'name': force_text(opts.verbose_name),
'obj': force_text(obj)
}
msg = _('The %(name)s "%(obj)s" was successfully recovered. '
'You may edit it again below.') % msg_dict
self.message_user(request, msg, messages.SUCCESS)
redirect_url = reverse(
'admin:%s_%s_change' % (opts.app_label, opts.model_name),
args=(pk_value,),
current_app=self.admin_site.name
)
# TODO: Check if there is next parameter and redirect to
# next, for cases of conflict solving.
redirect_url = add_preserved_filters({
'preserved_filters': preserved_filters,
'opts': opts,
}, redirect_url)
return HttpResponseRedirect(redirect_url)
else:
# populate form with regular data
form = RecoverObjectWithTranslationForm(**restore_form_kwargs)

context = {
'object': obj,
'version': version,
'revision': revision,
'revision_date': revision.date_created,
'conflict_links': conflicts_links_to_restore,
'non_resolvable_conflicts': non_reversible_by_user,
'versions': revision.version_set.order_by(
'content_type__name', 'object_id_int').all,
'object_name': force_text(self.model._meta.verbose_name),
'app_label': self.model._meta.app_label,
'opts': self.model._meta,
'add': False,
'change': True,
'save_as': False,
'has_add_permission': self.has_add_permission(request),
'has_change_permission': self.has_change_permission(
request, obj),
'has_delete_permission': self.has_delete_permission(
request, obj),
'has_file_field': True,
'has_absolute_url': False,
'original': obj,
}
# if there is no conflicts - add form to context.
if not conflicts_links_to_restore:
context['restore_form'] = form
return render(request, self.recover_confirmation_template, context)
Expand Up @@ -21,15 +21,6 @@
{% endblocktrans %}
</p>

{% if placeholders_to_restore %}
<p>{% trans 'The following placeholders were deleted and will be restored:' %}</p>
<ul>
{% for placeholder_version in placeholders_to_restore %}
<li>{{ placeholder_version.content_type.name|capfirst }} #{{ placeholder_version.object_id_int }}: {{ placeholder_version.object_repr }}</li>
{% endfor %}
</ul>
{% endif %}

{% if conflict_links %}
<h3>{% trans 'Warning there are conflicts' %}</h3>
<p>{% trans 'Please restore required related objects first:' %}</p>
Expand Down
56 changes: 0 additions & 56 deletions aldryn_reversion/tests/test_admin_views.py
Expand Up @@ -377,59 +377,3 @@ def test_admin_create_obj_view(self):
response = client.post(url, data={'position': position}, follow=True)
self.assertEqual(obj_count, SimpleRegistered.objects.count() - 1)
self.assertContains(response, position)


class AdminUtilsMethodsTestCase(AdminUtilsMixin,
CMSRequestBasedMixin,
HelperModelsObjectsSetupMixin,
ReversionBaseTestCase):

def test_create_aldryn_revision(self):
# would be used to get admin instance
with_placeholder_version = get_version_for_object(
self.with_placeholder)

admin_instance = self.get_admin_instance_for_object(
with_placeholder_version)
plugin = api.add_plugin(self.with_placeholder.content,
'TextPlugin', language='en')
plugin.body = 'Initial text'
plugin.save()
# ensure there was no versions for plugin before
self.assertEqual(
default_revision_manager.get_for_object(plugin).count(), 0)
with transaction.atomic():
with revision_context_manager.create_revision():
admin_instance._create_aldryn_revision(
plugin.placeholder,
comment='New aldryn revision with initial plugin')
# ensure there is at least one version after create aldryn revision
self. assertEqual(
default_revision_manager.get_for_object(plugin).count(), 1)
new_plugin_text = 'test plugin content was changed'
plugin.body = new_plugin_text
plugin.save()
with transaction.atomic():
with revision_context_manager.create_revision():
admin_instance._create_aldryn_revision(
plugin.placeholder,
comment='New aldryn revision with initial plugin')

# ensure there is at least one version after create aldryn revision
self. assertEqual(
default_revision_manager.get_for_object(plugin).count(), 2)
latest_plugin = plugin._meta.model.objects.get(pk=plugin.pk)

# ensure text is latest
self.assertEqual(latest_plugin.body, new_plugin_text)
# ensure text is initial if reverted to previous revision
prev_version = default_revision_manager.get_for_object(
self.with_placeholder)[1]
prev_version.revision.revert()
# refresh from db
latest_plugin = plugin._meta.model.objects.get(pk=plugin.pk)
# ensure plugin text was chagned. Note however that there might be
# different paths to ensure that text is chagned for CMSPlugin
# This only checks that plugin content (which is text plugin not the cms
# is reverted, so be careful.
self.assertEqual(latest_plugin.body, 'Initial text')
25 changes: 7 additions & 18 deletions aldryn_reversion/tests/test_forms.py
Expand Up @@ -10,14 +10,9 @@
)

from ..forms import RecoverObjectWithTranslationForm
from ..utils import (
RecursiveRevisionConflictResolver, get_deleted_placeholders_for_object,
)
from ..utils import RecursiveRevisionConflictResolver

from .base import (
ReversionBaseTestCase, HelperModelsObjectsSetupMixin,
get_version_for_object
)
from .base import ReversionBaseTestCase, HelperModelsObjectsSetupMixin, get_version_for_object


class FormsTestCase(HelperModelsObjectsSetupMixin, ReversionBaseTestCase):
Expand All @@ -30,7 +25,6 @@ def build_form_kwargs(self, obj):
'obj': obj,
'version': version,
'resolve_conflicts': [],
'placeholders': [],
}

def build_unbound_form(self, args_dict):
Expand Down Expand Up @@ -160,30 +154,25 @@ def test_recover_form_save(self):
self.assertEqual(SimpleNoAdmin.objects.count(), 1)

# test reverts object and deleted placeholders
with_placeholder_version = default_revision_manager.get_for_object(
self.with_placeholder)[0]
placeholder_pk = self.with_placeholder.content.pk
self.with_placeholder.content.delete()
# check that placeholder was actually deleted.
self.assertEqual(
Placeholder.objects.filter(pk=placeholder_pk).count(), 0)

placeholder_versions = get_deleted_placeholders_for_object(
self.with_placeholder, with_placeholder_version.revision)
form_with_placeholders_kwargs = self.build_form_kwargs(
self.with_placeholder)
self.with_placeholder.delete()
self.assertEqual(WithPlaceholder.objects.count(), 0)

form_with_placeholders_kwargs['placeholders'] = placeholder_versions
form_with_placeholder = self.build_bound_form(
form_with_placeholders_kwargs)
form_with_placeholder = self.build_bound_form(form_with_placeholders_kwargs)
self.assertTrue(form_with_placeholder.is_valid())
form_with_placeholder.save()

self.assertEqual(WithPlaceholder.objects.count(), 1)
# check that placeholder was restored
self.assertEqual(
Placeholder.objects.filter(pk=placeholder_pk).count(), 1)

# We don't deal with placeholder reversion anymore
self.assertFalse(Placeholder.objects.filter(pk=placeholder_pk).exists()) # TODO: review this logic

# test reverts object and translations
form_translated_kwargs = self.build_form_kwargs(self.with_translation)
Expand Down

0 comments on commit 4269e07

Please sign in to comment.