import base64 import os import re from io import BytesIO from django.core.files.uploadedfile import InMemoryUploadedFile from django.urls import reverse from PIL import Image from wiki.core.plugins import registry as plugin_registry from wiki.models import URLPath from wiki.plugins.images import models from wiki.plugins.images.wiki_plugin import ImagePlugin from ...base import ArticleWebTestUtils from ...base import DjangoClientTestBase from ...base import RequireRootArticleMixin from ...base import wiki_override_settings class ImageTests( RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase ): def setUp(self): super().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, path): # 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.assertGreaterEqual( plugin_index, 0, msg="Image plugin not activated" ) base_edit_url = reverse("wiki:edit", kwargs={"path": path}) url = base_edit_url + f"?f=form{plugin_index:d}" filestream = self._create_gif_filestream_from_base64(self.test_data) response = self.client.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.client.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) ) def get_article(self, cont, image): urlpath = URLPath.create_urlpath( URLPath.root(), "html_image", title="TestImage", content=cont ) if image: self._create_test_image(urlpath.path) return urlpath.article.render() def test_image_missing(self): output = self.get_article("[image:1]", False) expected = ( '
' '
Image not found
' '
' ) self.assertEqual(output, expected) def test_image_default(self): output = self.get_article("[image:1]", True) image_rev = models.Image.objects.get().current_revision.imagerevision expected = re.compile( r'
' r'' r'test\.gif' r'
' ) self.assertRegex(output, expected) def test_image_large_right(self): output = self.get_article("[image:1 align:right size:large]", True) image_rev = models.Image.objects.get().current_revision.imagerevision expected = re.compile( r'
' r'' r'test\.gif' r'
' ) self.assertRegex(output, expected) def test_image_orig(self): output = self.get_article("[image:1 size:orig]", True) image_rev = models.Image.objects.get().current_revision.imagerevision expected = ( '
' '' 'test.gif' '
' ) self.assertEqual(output, expected) # https://gist.github.com/guillaumepiot/817a70706587da3bd862835c59ef584e def generate_photo_file(self): file = BytesIO() image = Image.new("RGBA", size=(100, 100), color=(155, 0, 0)) image.save(file, "gif") file.name = "test.gif" file.seek(0) return file def test_add_revision(self): self._create_test_image(path="") image = models.Image.objects.get() before_edit_rev = image.current_revision.revision_number response = self.client.post( reverse( "wiki:images_add_revision", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ), data={"image": self.generate_photo_file()}, ) self.assertRedirects( response, reverse("wiki:edit", kwargs={"path": ""}) ) image = models.Image.objects.get() self.assertEqual(models.Image.objects.count(), 1) self.assertEqual( image.current_revision.previous_revision.revision_number, before_edit_rev, ) def test_delete_restore_revision(self): self._create_test_image(path="") image = models.Image.objects.get() before_edit_rev = image.current_revision.revision_number response = self.client.get( reverse( "wiki:images_delete", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ), ) self.assertRedirects( response, reverse("wiki:images_index", kwargs={"path": ""}) ) image = models.Image.objects.get() self.assertEqual(models.Image.objects.count(), 1) self.assertEqual( image.current_revision.previous_revision.revision_number, before_edit_rev, ) self.assertIs(image.current_revision.deleted, True) # RESTORE before_edit_rev = image.current_revision.revision_number response = self.client.get( reverse( "wiki:images_restore", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ), ) self.assertRedirects( response, reverse("wiki:images_index", kwargs={"path": ""}) ) image = models.Image.objects.get() self.assertEqual(models.Image.objects.count(), 1) self.assertEqual( image.current_revision.previous_revision.revision_number, before_edit_rev, ) self.assertFalse(image.current_revision.deleted) def test_purge(self): """ Tests that an image is really purged """ self._create_test_image(path="") image = models.Image.objects.get() image_revision = image.current_revision.imagerevision f_path = image_revision.image.file.name self.assertIs(os.path.exists(f_path), True) response = self.client.post( reverse( "wiki:images_purge", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ), data={"confirm": True}, ) self.assertRedirects( response, reverse("wiki:images_index", kwargs={"path": ""}) ) self.assertEqual(models.Image.objects.count(), 0) self.assertIs(os.path.exists(f_path), False) def test_add_revision_purge_image(self): """ Tests that an image with more than one revision is really purged """ # use another test to stage this one self.test_add_revision() image = models.Image.objects.get() image_revision = image.current_revision.imagerevision f_path = image_revision.image.file.name self.assertIs(os.path.exists(f_path), True) response = self.client.post( reverse( "wiki:images_purge", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ), data={"confirm": True}, ) self.assertRedirects( response, reverse("wiki:images_index", kwargs={"path": ""}) ) self.assertEqual(models.Image.objects.count(), 0) self.assertIs(os.path.exists(f_path), False) @wiki_override_settings(ACCOUNT_HANDLING=True) def test_login_on_revision_add(self): self._create_test_image(path="") self.client.logout() image = models.Image.objects.get() url = reverse( "wiki:images_add_revision", kwargs={ "article_id": self.root_article, "image_id": image.pk, "path": "", }, ) response = self.client.post( url, data={"image": self.generate_photo_file()} ) self.assertRedirects( response, "{}?next={}".format(reverse("wiki:login"), url) )