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.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import localdate
|
||||
from model_bakery import baker
|
||||
from pytest_django.asserts import assertHTMLEqual, assertInHTML, assertRedirects
|
||||
|
||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
||||
from core.models import Group, User
|
||||
from sas.baker_recipes import picture_recipe
|
||||
from sas.forms import AlbumEditForm
|
||||
from sas.models import Album, Picture
|
||||
|
||||
# Create your tests here.
|
||||
@@ -97,6 +95,7 @@ def test_main_page_content_anonymous(client: Client):
|
||||
@pytest.mark.django_db
|
||||
def test_album_access_non_subscriber(client: Client):
|
||||
"""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)
|
||||
user = baker.make(User)
|
||||
client.force_login(user)
|
||||
@@ -163,140 +162,6 @@ class TestAlbumUpload:
|
||||
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):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
Reference in New Issue
Block a user