~netlandish/django-wiki

16871365e6ddfc33ed79d87bd989348bd63af9c8 — Benjamin Bach 8 years ago a09f173 + c798ccb
Merge pull request #547 from benjaoming/restore-image-restoring

Restore image restoring
M docs/release_notes.rst => docs/release_notes.rst +1 -1
@@ 32,7 32,7 @@ django-wiki 0.1.2 (unreleased)
------------------------------

 * Remove unwanted items from default menu when ``WIKI_ACCOUNT_HANDLING = False``. #545

 * Fix broken soft-deletion and restoring of images, and "set revision" functionality #533

django-wiki 0.1.1
-----------------

M wiki/models/article.py => wiki/models/article.py +16 -0
@@ 308,6 308,22 @@ class BaseRevisionMixin(models.Model):
        elif settings.LOG_IPS_ANONYMOUS:
            self.ip_address = request.META.get('REMOTE_ADDR', None)

    def inherit_predecessor(self, predecessor):
        """
        This is a naive way of inheriting, assuming that ``predecessor`` is in
        fact the predecessor and there hasn't been any intermediate changes!

        :param: predecessor is an instance of whatever object for which
        object.current_revision implements BaseRevisionMixin.
        """
        predecessor = predecessor.current_revision
        self.previous_revision = predecessor
        self.deleted = predecessor.deleted
        self.locked = predecessor.locked
        self.deleted = predecessor.deleted
        self.locked = predecessor.locked
        self.revision_number = predecessor.revision_number + 1

    class Meta:
        abstract = True


M wiki/plugins/images/markdown_extensions.py => wiki/plugins/images/markdown_extensions.py +0 -1
@@ 12,7 12,6 @@ IMAGE_RE = re.compile(
    re.IGNORECASE)



class ImageExtension(markdown.Extension):

    """ Images plugin markdown extension for django-wiki. """

M wiki/plugins/images/models.py => wiki/plugins/images/models.py +6 -1
@@ 91,8 91,13 @@ class ImageRevision(RevisionPluginRevision):
        """
        Inherit certain properties from predecessor because it's very
        convenient. Remember to always call this method before
        setting properties :)"""
        setting properties :)

        A revision may not have a predecessor if the property is unset, it may
        be unset if it's the initial history entry.
        """
        predecessor = image.current_revision.imagerevision
        super(ImageRevision, self).inherit_predecessor(image)
        self.plugin = predecessor.plugin
        self.deleted = predecessor.deleted
        self.locked = predecessor.locked

M wiki/plugins/images/templates/wiki/plugins/images/index.html => wiki/plugins/images/templates/wiki/plugins/images/index.html +2 -2
@@ 36,7 36,7 @@
              {% trans "Upload and publish new image" %}
            </a> <br />
            <a href="{% url 'wiki:images_restore' path=urlpath.path article_id=article.id image_id=image.id %}">
              <span class="fa ra-repeat"></span>
              <span class="fa fa-refresh"></span>
              {% trans "Restore image" %}
            </a>
          {% else %}


@@ 84,7 84,7 @@
              <td>{{ old_revision.imagerevision.width }}x{{ old_revision.imagerevision.height }}</td>
              <td>
                {% if image|can_write:user and old_revision != image.current_revision %}
                  <a href="#">
                  <a href="{% url 'wiki:images_set_revision' path=urlpath.path article_id=article.id image_id=image.id rev_id=old_revision.id %}">
                    <span class="fa fa-refresh"></span>
                    {% trans "Revert to this version" %}
                  </a>

M wiki/plugins/images/templates/wiki/plugins/images/sidebar.html => wiki/plugins/images/templates/wiki/plugins/images/sidebar.html +1 -1
@@ 27,7 27,7 @@ function insert_image(image_id) {
      {% thumbnail revision.image "50x50" crop="center" as thumb %}
        <tr>
          <td style="white-space: nowrap;">
            <p>{% trans "Image id" %}: {{ image.id }}</code></p>
            <p>{% trans "Image id" %}: {{ image.id }}</p>
            <p>
              <a href="javascript:void(insert_image({{ image.id }}))"><span class="fa fa-edit"></span> {% trans "Insert" %}</a><br />
              {% if image|can_write:user %}

A wiki/plugins/images/tests/__init__.py => wiki/plugins/images/tests/__init__.py +6 -0
@@ 0,0 1,6 @@
from __future__ import absolute_import

import django
if django.VERSION < (1, 6):
    # New style autodiscovery of tests doesn't work for Django < 1.6
    from .test_views import *  # noqa

A wiki/plugins/images/tests/test_views.py => wiki/plugins/images/tests/test_views.py +87 -0
@@ 0,0 1,87 @@
from __future__ import print_function, unicode_literals

import base64
from io import BytesIO

from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.urlresolvers import reverse
from wiki.core.plugins import registry as plugin_registry
from wiki.tests.base import ArticleWebTestBase

from .. import models
from ..wiki_plugin import ImagePlugin


class ImageTests(ArticleWebTestBase):

    def setUp(self):
        super(ImageTests, self).setUp()
        self.article = self.root_article
        # A black 1x1 gif
        self.test_data = "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="

    def _create_gif_filestream_from_base64(self, str_base64, **kwargs):
        """
        Helper function to create filestream for upload.

        Parameters :
        strData : str, test string data

        Optional Arguments :
        filename : str, Defaults to 'test.txt'
        """
        filename = kwargs.get('filename', 'test.gif')
        data = base64.b64decode(str_base64)
        filedata = BytesIO(data)
        filestream = InMemoryUploadedFile(
            filedata,
            None,
            filename,
            'image',
            len(data),
            None
        )
        return filestream

    def _create_test_image(self):
        # Get the form index
        plugin_index = -1
        for cnt, plugin_instance in enumerate(plugin_registry.get_sidebar()):
            if isinstance(plugin_instance, ImagePlugin):
                plugin_index = cnt
                break
        self.assertTrue(plugin_index >= 0, "Image plugin not activated")
        base_edit_url = reverse('wiki:edit', kwargs={'path': ''})
        url = base_edit_url + '?f=form{0:d}'.format(plugin_index)
        filestream = self._create_gif_filestream_from_base64(self.test_data)
        response = self.c.post(
            url,
            {
                'unsaved_article_title': self.article.current_revision.title,
                'unsaved_article_content': self.article.current_revision.content,
                'image': filestream,
                'images_save': '1',
            },
        )
        self.assertRedirects(response, base_edit_url)

    def test_index(self):
        url = reverse('wiki:images_index', kwargs={'path': ''})
        response = self.c.get(url,)
        self.assertContains(response, 'Images')

    def test_upload(self):
        """
        Tests that simple file upload uploads correctly
        Uploading a file should preserve the original filename.
        Uploading should not modify file in any way.
        """
        self._create_test_image()
        # Check the object was created.
        image = models.Image.objects.get()
        image_revision = image.current_revision.imagerevision
        self.assertEqual(image_revision.get_filename(), 'test.gif')
        self.assertEqual(
            image_revision.image.file.read(),
            base64.b64decode(self.test_data)
        )

M wiki/plugins/images/views.py => wiki/plugins/images/views.py +13 -0
@@ 1,5 1,7 @@
from __future__ import absolute_import, unicode_literals

import logging

from django.contrib import messages
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404, redirect


@@ 10,9 12,12 @@ from django.views.generic.edit import FormView
from django.views.generic.list import ListView
from wiki.conf import settings as wiki_settings
from wiki.decorators import get_article
from wiki.models.pluginbase import RevisionPluginRevision
from wiki.plugins.images import forms, models
from wiki.views.mixins import ArticleMixin

logger = logging.getLogger(__name__)


class ImageView(ArticleMixin, ListView):



@@ 60,9 65,17 @@ class DeleteView(ArticleMixin, RedirectView):

    def get_redirect_url(self, **kwargs):

        if not self.image.current_revision:
            logger.critical('Encountered an image without current revision set, ID: {}'.format(self.image.id))
            latest_revision = RevisionPluginRevision.objects.filter(
                plugin=self.image
            ).latest('pk')
            self.image.current_revision = latest_revision

        new_revision = models.ImageRevision()
        new_revision.inherit_predecessor(self.image)
        new_revision.set_from_request(self.request)
        new_revision.revision_number = RevisionPluginRevision.objects.filter(plugin=self.image).count()
        new_revision.deleted = not self.restore
        new_revision.save()
        self.image.current_revision = new_revision

M wiki/plugins/images/wiki_plugin.py => wiki/plugins/images/wiki_plugin.py +1 -1
@@ 60,7 60,7 @@ class ImagePlugin(BasePlugin):
            name='images_purge'),
        url('^(?P<image_id>\d+)/revision/change/(?P<rev_id>\d+)/$',
            views.RevisionChangeView.as_view(),
            name='images_restore'),
            name='images_set_revision'),
        url('^(?P<image_id>\d+)/revision/add/$',
            views.RevisionAddView.as_view(),
            name='images_add_revision'),