mirror of
https://github.com/ae-utbm/sith.git
synced 2026-04-26 16:46:03 +00:00
test thumbnail management of AlbumEditForm
This commit is contained in:
@@ -0,0 +1,218 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Callable
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
|
from django.test import Client
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.datastructures import MultiValueDict
|
||||||
|
from django.utils.timezone import localdate
|
||||||
|
from model_bakery import baker
|
||||||
|
from PIL import Image
|
||||||
|
from pytest_django.asserts import assertInHTML, assertRedirects
|
||||||
|
|
||||||
|
from core.baker_recipes import subscriber_user
|
||||||
|
from core.models import Group, User
|
||||||
|
from core.utils import RED_PIXEL_PNG
|
||||||
|
from sas.baker_recipes import picture_recipe
|
||||||
|
from sas.forms import AlbumEditForm
|
||||||
|
from sas.models import Album
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def sas_root(db) -> Album:
|
||||||
|
return Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def album(db) -> Album:
|
||||||
|
name = "".join(
|
||||||
|
random.choice(string.ascii_letters) for _ in range(Album.NAME_MAX_LENGTH)
|
||||||
|
)
|
||||||
|
return baker.make(
|
||||||
|
Album, name=name, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("user", [None, lambda: baker.make(User), subscriber_user.make])
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_permission_denied(
|
||||||
|
client: Client, album: Album, user: Callable[[], User] | None
|
||||||
|
):
|
||||||
|
if user:
|
||||||
|
client.force_login(user())
|
||||||
|
url = reverse("sas:album_edit", kwargs={"album_id": album.pk})
|
||||||
|
for method in client.get, client.post:
|
||||||
|
assert method(url).status_code == 403
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_sas_root_read_only(client: Client, sas_root: Album):
|
||||||
|
moderator = baker.make(
|
||||||
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
||||||
|
)
|
||||||
|
client.force_login(moderator)
|
||||||
|
url = reverse("sas:album_edit", kwargs={"album_id": sas_root.pk})
|
||||||
|
for method in client.get, client.post:
|
||||||
|
assert method(url).status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("excluded", "is_valid"),
|
||||||
|
[
|
||||||
|
("name", False),
|
||||||
|
("date", False),
|
||||||
|
("file", True),
|
||||||
|
("parent", False),
|
||||||
|
("edit_groups", True),
|
||||||
|
("recursive", True),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_form_required(album: Album, excluded: str, is_valid: bool): # noqa: FBT001
|
||||||
|
data = {
|
||||||
|
"name": album.name,
|
||||||
|
"parent": baker.make(Album, parent=album.parent, is_moderated=True).pk,
|
||||||
|
"date": localdate(),
|
||||||
|
"file": "/random/path",
|
||||||
|
"edit_groups": [settings.SITH_GROUP_SAS_ADMIN_ID],
|
||||||
|
"recursive": False,
|
||||||
|
}
|
||||||
|
del data[excluded]
|
||||||
|
assert AlbumEditForm(data=data).is_valid() == is_valid
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_form_album_name(album: Album):
|
||||||
|
data = {
|
||||||
|
"name": "a" * Album.NAME_MAX_LENGTH,
|
||||||
|
"parent": album.pk,
|
||||||
|
"date": localdate(),
|
||||||
|
}
|
||||||
|
assert AlbumEditForm(data=data).is_valid()
|
||||||
|
|
||||||
|
data["name"] = "a" * (Album.NAME_MAX_LENGTH + 1)
|
||||||
|
assert not AlbumEditForm(data=data).is_valid()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_update_recursive_parent(client: Client, album: Album):
|
||||||
|
client.force_login(baker.make(User, is_superuser=True))
|
||||||
|
|
||||||
|
payload = {"name": album.name, "parent": album.pk, "date": localdate()}
|
||||||
|
response = client.post(
|
||||||
|
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
||||||
|
)
|
||||||
|
assertInHTML("<li>Boucle dans l'arborescence des dossiers</li>", response.text)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"user",
|
||||||
|
[
|
||||||
|
lambda: baker.make(User, is_superuser=True),
|
||||||
|
lambda: baker.make(
|
||||||
|
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"parent",
|
||||||
|
[
|
||||||
|
lambda: baker.make(
|
||||||
|
Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
||||||
|
),
|
||||||
|
lambda: Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_update(
|
||||||
|
client: Client,
|
||||||
|
album: Album,
|
||||||
|
sas_root: Album,
|
||||||
|
user: Callable[[], User],
|
||||||
|
parent: Callable[[], Album],
|
||||||
|
):
|
||||||
|
client.force_login(user())
|
||||||
|
expected_redirect = reverse("sas:album", kwargs={"album_id": album.pk})
|
||||||
|
payload = {
|
||||||
|
"name": "foo",
|
||||||
|
"parent": parent().id,
|
||||||
|
"date": localdate(),
|
||||||
|
"recursive": False,
|
||||||
|
}
|
||||||
|
response = client.post(
|
||||||
|
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
||||||
|
)
|
||||||
|
assertRedirects(response, expected_redirect)
|
||||||
|
album.refresh_from_db()
|
||||||
|
assert album.name == "foo"
|
||||||
|
assert album.parent.id == payload["parent"]
|
||||||
|
assert localdate(album.date) == localdate()
|
||||||
|
|
||||||
|
|
||||||
|
class TestAlbumThumbnail:
|
||||||
|
@pytest.fixture
|
||||||
|
def files(self):
|
||||||
|
return MultiValueDict(
|
||||||
|
{"file": [SimpleUploadedFile(name="foo.png", content=RED_PIXEL_PNG)]}
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_thumbnail_resized(self, album, files):
|
||||||
|
"""Test that album thumbnails are resized to the correct dimensions."""
|
||||||
|
form = AlbumEditForm(
|
||||||
|
data={"name": album.name, "date": localdate(), "parent": album.parent.id},
|
||||||
|
files=files,
|
||||||
|
instance=album,
|
||||||
|
)
|
||||||
|
assert form.is_valid()
|
||||||
|
form.save()
|
||||||
|
album.refresh_from_db()
|
||||||
|
assert album.file.name == f"SAS/{album.name}/thumb.webp"
|
||||||
|
assert Image.open(album.file).size == (200, 200)
|
||||||
|
|
||||||
|
def test_thumbnail_removed(self, album):
|
||||||
|
"""Test the case where the user checks the box to remove the thumbnail"""
|
||||||
|
album.file = ContentFile(name="foo.png", content=RED_PIXEL_PNG)
|
||||||
|
album.save()
|
||||||
|
previous_filename = album.file.name
|
||||||
|
form = AlbumEditForm(
|
||||||
|
data={
|
||||||
|
"name": "foo",
|
||||||
|
"date": localdate(),
|
||||||
|
"parent": album.parent.id,
|
||||||
|
"file-clear": True,
|
||||||
|
},
|
||||||
|
instance=album,
|
||||||
|
)
|
||||||
|
# as there is now no picture, a thumbnail should be generated
|
||||||
|
with patch.object(Album, "generate_thumbnail") as mock:
|
||||||
|
assert form.is_valid()
|
||||||
|
form.save()
|
||||||
|
album.refresh_from_db()
|
||||||
|
assert album.file.storage.exists(album.file.name)
|
||||||
|
assert not album.file.storage.exists(previous_filename)
|
||||||
|
mock.assert_called_once()
|
||||||
|
|
||||||
|
def test_generate_thumbnail(self, album):
|
||||||
|
"""Test that if no image is given and the album has pictures,
|
||||||
|
the thumbnail is automatically generated.
|
||||||
|
"""
|
||||||
|
picture = picture_recipe.make(
|
||||||
|
parent=album, thumbnail=ContentFile(name="foo.png", content=RED_PIXEL_PNG)
|
||||||
|
)
|
||||||
|
form = AlbumEditForm(
|
||||||
|
data={"name": "foo", "date": localdate(), "parent": album.parent.id},
|
||||||
|
instance=album,
|
||||||
|
)
|
||||||
|
assert form.is_valid()
|
||||||
|
form.save()
|
||||||
|
album.refresh_from_db()
|
||||||
|
assert Path(album.file.name) == Path("SAS/foo/thumb.webp")
|
||||||
|
assert album.file.storage.exists(album.file.name)
|
||||||
|
assert Image.open(album.file) == Image.open(picture.thumbnail)
|
||||||
+1
-136
@@ -20,14 +20,12 @@ from django.conf import settings
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.timezone import localdate
|
|
||||||
from model_bakery import baker
|
from model_bakery import baker
|
||||||
from pytest_django.asserts import assertHTMLEqual, assertInHTML, assertRedirects
|
from pytest_django.asserts import assertHTMLEqual, assertInHTML, assertRedirects
|
||||||
|
|
||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||||
from core.models import Group, User
|
from core.models import Group, User
|
||||||
from sas.baker_recipes import picture_recipe
|
from sas.baker_recipes import picture_recipe
|
||||||
from sas.forms import AlbumEditForm
|
|
||||||
from sas.models import Album, Picture
|
from sas.models import Album, Picture
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
@@ -97,6 +95,7 @@ def test_main_page_content_anonymous(client: Client):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_album_access_non_subscriber(client: Client):
|
def test_album_access_non_subscriber(client: Client):
|
||||||
"""Test that non-subscribers can only access albums where they are identified."""
|
"""Test that non-subscribers can only access albums where they are identified."""
|
||||||
|
cache.clear()
|
||||||
album = baker.make(Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID)
|
album = baker.make(Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID)
|
||||||
user = baker.make(User)
|
user = baker.make(User)
|
||||||
client.force_login(user)
|
client.force_login(user)
|
||||||
@@ -163,140 +162,6 @@ class TestAlbumUpload:
|
|||||||
assert not album.children.exists()
|
assert not album.children.exists()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
class TestAlbumEdit:
|
|
||||||
@pytest.fixture
|
|
||||||
def sas_root(self) -> Album:
|
|
||||||
return Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID)
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def album(self) -> Album:
|
|
||||||
return baker.make(
|
|
||||||
Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"user",
|
|
||||||
[None, lambda: baker.make(User), subscriber_user.make],
|
|
||||||
)
|
|
||||||
def test_permission_denied(
|
|
||||||
self,
|
|
||||||
client: Client,
|
|
||||||
album: Album,
|
|
||||||
user: Callable[[], User] | None,
|
|
||||||
):
|
|
||||||
if user:
|
|
||||||
client.force_login(user())
|
|
||||||
|
|
||||||
url = reverse("sas:album_edit", kwargs={"album_id": album.pk})
|
|
||||||
response = client.get(url)
|
|
||||||
assert response.status_code == 403
|
|
||||||
response = client.post(url)
|
|
||||||
assert response.status_code == 403
|
|
||||||
|
|
||||||
def test_sas_root_read_only(self, client: Client, sas_root: Album):
|
|
||||||
moderator = baker.make(
|
|
||||||
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
|
||||||
)
|
|
||||||
client.force_login(moderator)
|
|
||||||
url = reverse("sas:album_edit", kwargs={"album_id": sas_root.pk})
|
|
||||||
response = client.get(url)
|
|
||||||
assert response.status_code == 404
|
|
||||||
response = client.post(url)
|
|
||||||
assert response.status_code == 404
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("excluded", "is_valid"),
|
|
||||||
[
|
|
||||||
("name", False),
|
|
||||||
("date", False),
|
|
||||||
("file", True),
|
|
||||||
("parent", False),
|
|
||||||
("edit_groups", True),
|
|
||||||
("recursive", True),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_form_required(self, album: Album, excluded: str, is_valid: bool): # noqa: FBT001
|
|
||||||
data = {
|
|
||||||
"name": album.name[: Album.NAME_MAX_LENGTH],
|
|
||||||
"parent": baker.make(Album, parent=album.parent, is_moderated=True).pk,
|
|
||||||
"date": localdate().strftime("%Y-%m-%d"),
|
|
||||||
"file": "/random/path",
|
|
||||||
"edit_groups": [settings.SITH_GROUP_SAS_ADMIN_ID],
|
|
||||||
"recursive": False,
|
|
||||||
}
|
|
||||||
del data[excluded]
|
|
||||||
assert AlbumEditForm(data=data).is_valid() == is_valid
|
|
||||||
|
|
||||||
def test_form_album_name(self, album: Album):
|
|
||||||
data = {
|
|
||||||
"name": album.name[: Album.NAME_MAX_LENGTH],
|
|
||||||
"parent": album.pk,
|
|
||||||
"date": localdate().strftime("%Y-%m-%d"),
|
|
||||||
}
|
|
||||||
assert AlbumEditForm(data=data).is_valid()
|
|
||||||
|
|
||||||
data["name"] = album.name[: Album.NAME_MAX_LENGTH + 1]
|
|
||||||
assert not AlbumEditForm(data=data).is_valid()
|
|
||||||
|
|
||||||
def test_update_recursive_parent(self, client: Client, album: Album):
|
|
||||||
client.force_login(baker.make(User, is_superuser=True))
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"name": album.name[: Album.NAME_MAX_LENGTH],
|
|
||||||
"parent": album.pk,
|
|
||||||
"date": localdate().strftime("%Y-%m-%d"),
|
|
||||||
}
|
|
||||||
response = client.post(
|
|
||||||
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
|
||||||
)
|
|
||||||
assertInHTML("<li>Boucle dans l'arborescence des dossiers</li>", response.text)
|
|
||||||
assert response.status_code == 200
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"user",
|
|
||||||
[
|
|
||||||
lambda: baker.make(User, is_superuser=True),
|
|
||||||
lambda: baker.make(
|
|
||||||
User, groups=[Group.objects.get(pk=settings.SITH_GROUP_SAS_ADMIN_ID)]
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"parent",
|
|
||||||
[
|
|
||||||
lambda: baker.make(
|
|
||||||
Album, parent_id=settings.SITH_SAS_ROOT_DIR_ID, is_moderated=True
|
|
||||||
),
|
|
||||||
lambda: Album.objects.get(id=settings.SITH_SAS_ROOT_DIR_ID),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_update(
|
|
||||||
self,
|
|
||||||
client: Client,
|
|
||||||
album: Album,
|
|
||||||
sas_root: Album,
|
|
||||||
user: Callable[[], User],
|
|
||||||
parent: Callable[[], Album],
|
|
||||||
):
|
|
||||||
client.force_login(user())
|
|
||||||
expected_redirect = reverse("sas:album", kwargs={"album_id": album.pk})
|
|
||||||
payload = {
|
|
||||||
"name": album.name[: Album.NAME_MAX_LENGTH],
|
|
||||||
"parent": parent().id,
|
|
||||||
"date": localdate().strftime("%Y-%m-%d"),
|
|
||||||
"recursive": False,
|
|
||||||
}
|
|
||||||
response = client.post(
|
|
||||||
reverse("sas:album_edit", kwargs={"album_id": album.pk}), payload
|
|
||||||
)
|
|
||||||
assertRedirects(response, expected_redirect)
|
|
||||||
album.refresh_from_db()
|
|
||||||
assert album.name == payload["name"]
|
|
||||||
assert album.parent.id == payload["parent"]
|
|
||||||
assert localdate(album.date) == localdate()
|
|
||||||
|
|
||||||
|
|
||||||
class TestSasModeration(TestCase):
|
class TestSasModeration(TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|||||||
Reference in New Issue
Block a user