mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-03 18:43:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			175 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from dataclasses import dataclass
 | 
						|
from datetime import timedelta
 | 
						|
from pathlib import Path
 | 
						|
 | 
						|
import pytest
 | 
						|
from django.conf import settings
 | 
						|
from django.contrib.auth.models import Permission
 | 
						|
from django.http import HttpResponse
 | 
						|
from django.test import Client, TestCase
 | 
						|
from django.urls import reverse
 | 
						|
from django.utils.timezone import now
 | 
						|
from model_bakery import baker, seq
 | 
						|
from pytest_django.asserts import assertNumQueries
 | 
						|
 | 
						|
from com.ics_calendar import IcsCalendar
 | 
						|
from com.models import News, NewsDate
 | 
						|
from core.markdown import markdown
 | 
						|
from core.models import User
 | 
						|
 | 
						|
 | 
						|
@dataclass
 | 
						|
class MockResponse:
 | 
						|
    ok: bool
 | 
						|
    value: str
 | 
						|
 | 
						|
    @property
 | 
						|
    def content(self):
 | 
						|
        return self.value.encode("utf8")
 | 
						|
 | 
						|
 | 
						|
def accel_redirect_to_file(response: HttpResponse) -> Path | None:
 | 
						|
    redirect = Path(response.headers.get("X-Accel-Redirect", ""))
 | 
						|
    if not redirect.is_relative_to(Path("/") / settings.MEDIA_ROOT.stem):
 | 
						|
        return None
 | 
						|
    return settings.MEDIA_ROOT / redirect.relative_to(
 | 
						|
        Path("/") / settings.MEDIA_ROOT.stem
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.django_db
 | 
						|
class TestInternalCalendar:
 | 
						|
    @pytest.fixture(autouse=True)
 | 
						|
    def clear_cache(self):
 | 
						|
        IcsCalendar._INTERNAL_CALENDAR.unlink(missing_ok=True)
 | 
						|
 | 
						|
    def test_fetch_success(self, client: Client):
 | 
						|
        response = client.get(reverse("api:calendar_internal"))
 | 
						|
        assert response.status_code == 200
 | 
						|
        out_file = accel_redirect_to_file(response)
 | 
						|
        assert out_file is not None
 | 
						|
        assert out_file.exists()
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.django_db
 | 
						|
class TestModerateNews:
 | 
						|
    @pytest.mark.parametrize("news_is_published", [True, False])
 | 
						|
    def test_moderation_ok(self, client: Client, news_is_published: bool):  # noqa FBT
 | 
						|
        user = baker.make(
 | 
						|
            User, user_permissions=[Permission.objects.get(codename="moderate_news")]
 | 
						|
        )
 | 
						|
        # The API call should work even if the news is initially moderated.
 | 
						|
        # In the latter case, the result should be a noop, rather than an error.
 | 
						|
        news = baker.make(News, is_published=news_is_published)
 | 
						|
        initial_moderator = news.moderator
 | 
						|
        client.force_login(user)
 | 
						|
        response = client.patch(
 | 
						|
            reverse("api:moderate_news", kwargs={"news_id": news.id})
 | 
						|
        )
 | 
						|
        # if it wasn't moderated, it should now be moderated and the moderator should
 | 
						|
        # be the user that made the request.
 | 
						|
        # If it was already moderated, it should be a no-op, but not an error
 | 
						|
        assert response.status_code == 200
 | 
						|
        news.refresh_from_db()
 | 
						|
        assert news.is_published
 | 
						|
        if not news_is_published:
 | 
						|
            assert news.moderator == user
 | 
						|
        else:
 | 
						|
            assert news.moderator == initial_moderator
 | 
						|
 | 
						|
    def test_moderation_forbidden(self, client: Client):
 | 
						|
        user = baker.make(User)
 | 
						|
        news = baker.make(News, is_published=False)
 | 
						|
        client.force_login(user)
 | 
						|
        response = client.patch(
 | 
						|
            reverse("api:moderate_news", kwargs={"news_id": news.id})
 | 
						|
        )
 | 
						|
        assert response.status_code == 403
 | 
						|
        news.refresh_from_db()
 | 
						|
        assert not news.is_published
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.django_db
 | 
						|
class TestDeleteNews:
 | 
						|
    def test_delete_news_ok(self, client: Client):
 | 
						|
        user = baker.make(
 | 
						|
            User, user_permissions=[Permission.objects.get(codename="delete_news")]
 | 
						|
        )
 | 
						|
        news = baker.make(News)
 | 
						|
        client.force_login(user)
 | 
						|
        response = client.delete(
 | 
						|
            reverse("api:delete_news", kwargs={"news_id": news.id})
 | 
						|
        )
 | 
						|
        assert response.status_code == 200
 | 
						|
        assert not News.objects.filter(id=news.id).exists()
 | 
						|
 | 
						|
    def test_delete_news_forbidden(self, client: Client):
 | 
						|
        user = baker.make(User)
 | 
						|
        news = baker.make(News)
 | 
						|
        client.force_login(user)
 | 
						|
        response = client.delete(
 | 
						|
            reverse("api:delete_news", kwargs={"news_id": news.id})
 | 
						|
        )
 | 
						|
        assert response.status_code == 403
 | 
						|
        assert News.objects.filter(id=news.id).exists()
 | 
						|
 | 
						|
 | 
						|
class TestFetchNewsDates(TestCase):
 | 
						|
    @classmethod
 | 
						|
    def setUpTestData(cls):
 | 
						|
        News.objects.all().delete()
 | 
						|
        cls.dates = baker.make(
 | 
						|
            NewsDate,
 | 
						|
            _quantity=5,
 | 
						|
            _bulk_create=True,
 | 
						|
            start_date=seq(value=now(), increment_by=timedelta(days=1)),
 | 
						|
            end_date=seq(
 | 
						|
                value=now() + timedelta(hours=2), increment_by=timedelta(days=1)
 | 
						|
            ),
 | 
						|
            news=iter(
 | 
						|
                baker.make(News, is_published=True, _quantity=5, _bulk_create=True)
 | 
						|
            ),
 | 
						|
        )
 | 
						|
        cls.dates.append(
 | 
						|
            baker.make(
 | 
						|
                NewsDate,
 | 
						|
                start_date=now() + timedelta(days=2, hours=1),
 | 
						|
                end_date=now() + timedelta(days=2, hours=5),
 | 
						|
                news=baker.make(News, is_published=True),
 | 
						|
            )
 | 
						|
        )
 | 
						|
        cls.dates.sort(key=lambda d: d.start_date)
 | 
						|
 | 
						|
    def test_num_queries(self):
 | 
						|
        with assertNumQueries(2):
 | 
						|
            self.client.get(reverse("api:fetch_news_dates"))
 | 
						|
 | 
						|
    def test_html_format(self):
 | 
						|
        """Test that when the summary is asked in html, the summary is in html."""
 | 
						|
        summary_1 = "# First event\nThere is something happening.\n"
 | 
						|
        self.dates[0].news.summary = summary_1
 | 
						|
        self.dates[0].news.save()
 | 
						|
        summary_2 = (
 | 
						|
            "# Second event\n"
 | 
						|
            "There is something happening **for real**.\n"
 | 
						|
            "Everything is [here](https://youtu.be/dQw4w9WgXcQ)\n"
 | 
						|
        )
 | 
						|
        self.dates[1].news.summary = summary_2
 | 
						|
        self.dates[1].news.save()
 | 
						|
        response = self.client.get(
 | 
						|
            reverse("api:fetch_news_dates") + "?page_size=2&text_format=html"
 | 
						|
        )
 | 
						|
        assert response.status_code == 200
 | 
						|
        dates = response.json()["results"]
 | 
						|
        assert dates[0]["news"]["summary"] == markdown(summary_1)
 | 
						|
        assert dates[1]["news"]["summary"] == markdown(summary_2)
 | 
						|
 | 
						|
    def test_fetch(self):
 | 
						|
        after = (now() + timedelta(days=1)).isoformat()
 | 
						|
        response = self.client.get(
 | 
						|
            reverse("api:fetch_news_dates", query={"page_size": 3, "after": after})
 | 
						|
        )
 | 
						|
        assert response.status_code == 200
 | 
						|
        dates = response.json()["results"]
 | 
						|
        assert [d["id"] for d in dates] == [d.id for d in self.dates[1:4]]
 |