mamweb/galerie/tests.py
2025-12-21 19:46:45 +00:00

206 lines
8.7 KiB
Python

from django.conf import settings
from django.contrib.admin.sites import AdminSite
from django.contrib.contenttypes.models import ContentType
from django.http import HttpRequest
from django.test import TestCase, Client, override_settings
from django.urls import reverse
from galerie.models import Galerie, Soubor
from soustredeni.models import Soustredeni
import django.contrib.auth.models as auth
import personalni.models as pers
import tvorba.models as tv
import galerie.admin as g_adm
from contextlib import ExitStack
from pathlib import Path
import shutil
import tempfile
# NOTE: Existují metody, jak si pořídit kontext: https://docs.python.org/3/library/unittest.html#unittest.TestCase.enterClassContext
# Nepoužíváme je, protože jsem nepřišlo na to, jak je pak použít v `@override_settings(MEDIA_ROOT=media_dir)`
# Ref: https://stackoverflow.com/a/2269295
tempdir = tempfile.TemporaryDirectory(prefix='mamweb_test')
media_dir = Path(tempdir.name) / 'media'
class GalerieTests(TestCase):
@classmethod
def setUpTestData(cls):
org_perm = auth.Permission.objects.get(content_type=ContentType.objects.get_for_model(auth.User), codename='org')
resitel_perm = auth.Permission.objects.get(content_type=ContentType.objects.get_for_model(auth.User), codename='resitel')
r = tv.Rocnik.objects.create(rocnik=42, prvni_rok=1970)
cls.sous_a = Soustredeni.objects.create(rocnik=r)
cls.sous_b = Soustredeni.objects.create(rocnik=r)
cls.neucastnik = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ne')))
cls.neucastnik.osoba.user.user_permissions.add(resitel_perm)
cls.ucastnik_a = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ua')))
cls.ucastnik_a.osoba.user.user_permissions.add(resitel_perm)
cls.sous_a.ucastnici.add(cls.ucastnik_a)
cls.ucastnik_b = pers.Resitel.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='ub')))
cls.ucastnik_b.osoba.user.user_permissions.add(resitel_perm)
cls.sous_b.ucastnici.add(cls.ucastnik_b)
cls.org = pers.Organizator.objects.create(osoba=pers.Osoba.objects.create(user=auth.User.objects.create_user(username='o', is_staff=True)))
cls.org.osoba.user.user_permissions.add(org_perm)
def setUp(self):
media_dir.mkdir()
def tearDown(self):
shutil.rmtree(media_dir)
@classmethod
def tearDownClass(cls):
super().tearDownClass()
tempdir.cleanup()
# TODO: tohle není moc unit test. Správnější by bylo mít polopřipravené
# věci (sous s galerií, sous bez galerie, sous se špatně uspořádanými
# galeriemi ap.) a dedikované testy na jednotlivé úkony. Ale teď jsem to
# začalo psát takhle a chci to nejdřív dopsat a commitnout, takže pokud to
# zapomenu rozstřelit na menší, tak to takhle zůstane…
@override_settings(MEDIA_ROOT=media_dir)
def test_vyrobeni_galerii_k_sousu(self):
"""Vyrobí strukturu galerií odpovídající sousové běžné struktuře pomocí příslušných views"""
org_client = Client()
org_client.force_login(self.org.osoba.user)
resp = org_client.get(reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': 0}))
self.assertEqual(resp.status_code, 200)
tf = Path(settings.BASE_DIR) / 'galerie' / 'testfiles'
filenames_pa = [
tf / 'kod_emoji.jpg',
tf / 'metal.jpg',
tf / 'ohno_small.jpg',
]
filenames_so = [
tf / 'pf2020_small.jpg',
]
resp = org_client.post(
reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': 0}),
data={'nazev': 'Top galerie k sousu A'},
follow=True,
)
self.assertEqual(resp.status_code, 200)
# Teď je kind-of těžké kliknout na „přidat novou podgalerii“, protože ten odkaz je někde v HTML vyrenderovaný templatem.
# Ale můžeme vytáhnout pk galerie z kontextu
top_gal = resp.context['galerie']
self.assertIsInstance(top_gal, Galerie)
# Záměrně vyrobíme nejdřív sobotní a pak páteční galerii, ať je pak můžeme prohodit
with ExitStack() as stack:
files = [stack.enter_context(open(fn, 'rb')) for fn in filenames_so]
resp = org_client.post(
reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk}),
data={'nazev': 'Sobota', 'obr': files},
follow=True,
)
self.assertEqual(resp.status_code, 200)
so_gal = resp.context['galerie']
self.assertIsInstance(so_gal, Galerie)
with ExitStack() as stack:
files = [stack.enter_context(open(fn, 'rb')) for fn in filenames_pa]
resp = org_client.post(
reverse('galerie_nova', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk}),
data={'nazev': 'Pátek', 'obr': files},
follow=True,
)
self.assertEqual(resp.status_code, 200)
pa_gal = resp.context['galerie']
self.assertIsInstance(pa_gal, Galerie)
self.assertGreater(pa_gal.poradi, so_gal.poradi)
# Dokonce i tušíme, jaká ta pořadí jsou
# NOTE: pokud tohle začne failovat, tak je asi safe to smazat.
self.assertEqual(pa_gal.poradi, 2)
self.assertEqual(so_gal.poradi, 1)
# Teď je prohodíme:
# NOTE: použití metody PATCH by tady prošlo, protože nekontrolujeme,
# jaká metoda se používá. Ale dokud simulujeme orga na webu s odkazy
# (`<a>`), tak použijeme GET.
resp = org_client.get(
reverse('galerie_doleva', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk, 'subgalerie': pa_gal.pk}),
follow=True,
)
self.assertEqual(resp.status_code, 200)
resp = org_client.get(
reverse('galerie_doprava', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk, 'subgalerie': so_gal.pk}),
follow=True,
)
self.assertEqual(resp.status_code, 200)
# Změnil se stav
pa_gal.refresh_from_db()
so_gal.refresh_from_db()
self.assertLess(pa_gal.poradi, so_gal.poradi)
self.assertEqual(pa_gal.poradi, 1)
self.assertEqual(so_gal.poradi, 2)
# Ověříme, že v galeriích jsou obrázky
self.assertEqual(top_gal.soubor_set.count(), 0) # FIXME: related_name
self.assertEqual(top_gal.podgalerie.count(), 2)
self.assertEqual(pa_gal.podgalerie.count(), 0)
self.assertEqual(pa_gal.soubor_set.count(), 3)
self.assertEqual(so_gal.podgalerie.count(), 0)
self.assertEqual(so_gal.soubor_set.count(), 1)
# Zveřejníme galerii (už ne pomocí org_clienta, bo se to dělá v Adminu, ale tu admin action použít chceme umět)
# Otestujeme práva, že ještě veřejná není
self.assertEqual(top_gal.zobrazit, Galerie.Viditelnost.ORG)
self.assertEqual(pa_gal.zobrazit, Galerie.Viditelnost.ORG)
self.assertEqual(so_gal.zobrazit, Galerie.Viditelnost.ORG)
# (použití Admina zkopírováno z personalni.tests, což odkazuje na https://www.argpar.se/posts/programming/testing-django-admin/
adm_site = AdminSite()
galerieadmin = g_adm.GalerieAdmin(Galerie, adm_site)
# Sobotní galerie budiž jen pro účastníky
so_gal.zobrazit = Galerie.Viditelnost.UCASTNIK
so_gal.save()
# FIXME: queryset z literálu
g_adm.zverejnit_fotogalerii(galerieadmin, HttpRequest(), Galerie.objects.filter(pk=top_gal.pk))
top_gal.refresh_from_db()
pa_gal.refresh_from_db()
so_gal.refresh_from_db()
# Otestujeme práva
self.assertEqual(top_gal.zobrazit, Galerie.Viditelnost.VZDY)
self.assertEqual(pa_gal.zobrazit, Galerie.Viditelnost.VZDY)
self.assertEqual(so_gal.zobrazit, Galerie.Viditelnost.UCASTNIK)
# otestujeme i že jde dělat requesty
url_top = reverse('galerie_galerie', kwargs={'soustredeni': self.sous_a.id, 'galerie': top_gal.pk})
url_pa = reverse('galerie_galerie', kwargs={'soustredeni': self.sous_a.id, 'galerie': pa_gal.pk})
url_so = reverse('galerie_galerie', kwargs={'soustredeni': self.sous_a.id, 'galerie': so_gal.pk})
url_pa_soub = [reverse('galerie_soubor', kwargs={'soustredeni': self.sous_a.id, 'galerie': pa_gal.pk, 'soubor': s.pk}) for s in pa_gal.soubor_set.all()]
url_so_soub = [reverse('galerie_soubor', kwargs={'soustredeni': self.sous_a.id, 'galerie': so_gal.pk, 'soubor': s.pk}) for s in so_gal.soubor_set.all()]
verejne_url = [url_top, url_pa] + url_pa_soub
ucastnik_url = [url_so] + url_so_soub
# TODO: mít org-only galerii?
uc_client = Client()
uc_client.force_login(self.ucastnik_a.osoba.user)
ucb_client = Client()
ucb_client.force_login(self.ucastnik_b.osoba.user)
neuc_client = Client()
neuc_client.force_login(self.neucastnik.osoba.user)
verej_client = Client()
NESMI_ZOBRAZIT = 404
for url in ucastnik_url:
for cl, status in (
(org_client, 200),
(uc_client, 200),
(ucb_client, NESMI_ZOBRAZIT),
(neuc_client, NESMI_ZOBRAZIT),
(verej_client, NESMI_ZOBRAZIT),
):
resp = cl.get(url)
self.assertEqual(resp.status_code, status)
for url in verejne_url:
for cl in (org_client, uc_client, ucb_client, neuc_client, verej_client):
resp = cl.get(url)
self.assertEqual(resp.status_code, 200)