diff options
author | 2023-12-14 20:28:17 +0800 | |
---|---|---|
committer | 2023-12-14 20:28:17 +0800 | |
commit | 449c08fd5459b2f804dbf825086ec1dd0f244d8a (patch) | |
tree | e4589cb227cdb2e611bcbf9b02ea481fe24cdb34 /pydis_site/apps/home | |
parent | Resize theme switch (diff) | |
parent | Merge pull request #1173 from python-discord/dependabot/pip/sentry-sdk-1.39.0 (diff) |
Fix all conflicts
hopefully I dont have to do this again
Diffstat (limited to 'pydis_site/apps/home')
-rw-r--r-- | pydis_site/apps/home/README.md | 35 | ||||
-rw-r--r-- | pydis_site/apps/home/models.py (renamed from pydis_site/apps/home/models/repository_metadata.py) | 0 | ||||
-rw-r--r-- | pydis_site/apps/home/models/__init__.py | 3 | ||||
-rw-r--r-- | pydis_site/apps/home/tests/test_repodata_helpers.py | 25 | ||||
-rw-r--r-- | pydis_site/apps/home/tests/test_views.py | 5 | ||||
-rw-r--r-- | pydis_site/apps/home/views.py (renamed from pydis_site/apps/home/views/home.py) | 32 | ||||
-rw-r--r-- | pydis_site/apps/home/views/__init__.py | 3 |
7 files changed, 66 insertions, 37 deletions
diff --git a/pydis_site/apps/home/README.md b/pydis_site/apps/home/README.md new file mode 100644 index 00000000..34c1e367 --- /dev/null +++ b/pydis_site/apps/home/README.md @@ -0,0 +1,35 @@ +# The "home" app + +This Django application takes care of serving the homepage of our website, that +is, the first page that you see when you open pythondiscord.com. It also +manages the timeline page showcasing the history of our community. + +## Directory structure + +- `migrations` is the standard Django migrations folder. As with [the API + app](../api/README.md), you usually won't need to edit this manually, use + `python manage.py makemigrations [-n short_description]` to create a new + migration here. + +- `templatetags` contains custom [template tags and + filters](https://docs.djangoproject.com/en/dev/howto/custom-template-tags/) + used in the home app. + +- `tests` contains unit tests that validate the home app works as expected. If + you're looking for guidance in writing tests, the [Django tutorial + introducing automated + testing](https://docs.djangoproject.com/en/dev/intro/tutorial05/) is a great + starting point. + +As for the Python modules residing directly in here: + +- `models.py` contains our Django model definitions for this app. As this app + is rather minimal, this is kept as a single module - more models would be + split up into a subfolder as in the other apps. + +- `urls.py` configures Django's [URL + dispatcher](https://docs.djangoproject.com/en/dev/topics/http/urls/) for our + home endpoints. + +- `views.py` contains our Django views. You can see where they are linked in the + URL dispatcher. diff --git a/pydis_site/apps/home/models/repository_metadata.py b/pydis_site/apps/home/models.py index 00a83cd7..00a83cd7 100644 --- a/pydis_site/apps/home/models/repository_metadata.py +++ b/pydis_site/apps/home/models.py diff --git a/pydis_site/apps/home/models/__init__.py b/pydis_site/apps/home/models/__init__.py deleted file mode 100644 index 6c68df9c..00000000 --- a/pydis_site/apps/home/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .repository_metadata import RepositoryMetadata - -__all__ = ["RepositoryMetadata"] diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py index 5634bc9b..acf4a817 100644 --- a/pydis_site/apps/home/tests/test_repodata_helpers.py +++ b/pydis_site/apps/home/tests/test_repodata_helpers.py @@ -22,7 +22,7 @@ def mocked_requests_get(*args, **kwargs) -> "MockResponse": # noqa: F821 if args[0] == HomeView.github_api: json_path = Path(__file__).resolve().parent / "mock_github_api_response.json" - with open(json_path, 'r') as json_file: + with open(json_path) as json_file: mock_data = json.load(json_file) return MockResponse(mock_data, 200) @@ -36,13 +36,13 @@ class TestRepositoryMetadataHelpers(TestCase): """Executed before each test method.""" self.home_view = HomeView() - @mock.patch('requests.get', side_effect=mocked_requests_get) + @mock.patch('httpx.get', side_effect=mocked_requests_get) def test_returns_metadata(self, _: mock.MagicMock): """Test if the _get_repo_data helper actually returns what it should.""" metadata = self.home_view._get_repo_data() self.assertIsInstance(metadata[0], RepositoryMetadata) - self.assertEquals(len(metadata), len(self.home_view.repos)) + self.assertEqual(len(metadata), len(self.home_view.repos)) def test_returns_cached_metadata(self): """Test if the _get_repo_data helper returns cached data when available.""" @@ -59,7 +59,7 @@ class TestRepositoryMetadataHelpers(TestCase): self.assertIsInstance(metadata[0], RepositoryMetadata) self.assertIsInstance(str(metadata[0]), str) - @mock.patch('requests.get', side_effect=mocked_requests_get) + @mock.patch('httpx.get', side_effect=mocked_requests_get) def test_refresh_stale_metadata(self, _: mock.MagicMock): """Test if the _get_repo_data helper will refresh when the data is stale.""" repo_data = RepositoryMetadata( @@ -75,18 +75,18 @@ class TestRepositoryMetadataHelpers(TestCase): self.assertIsInstance(metadata[0], RepositoryMetadata) - @mock.patch('requests.get', side_effect=mocked_requests_get) + @mock.patch('httpx.get', side_effect=mocked_requests_get) def test_returns_api_data(self, _: mock.MagicMock): """Tests if the _get_api_data helper returns what it should.""" api_data = self.home_view._get_api_data() repo = self.home_view.repos[0] self.assertIsInstance(api_data, dict) - self.assertEquals(len(api_data), len(self.home_view.repos)) + self.assertEqual(len(api_data), len(self.home_view.repos)) self.assertIn(repo, api_data.keys()) self.assertIn("stargazers_count", api_data[repo]) - @mock.patch('requests.get', side_effect=mocked_requests_get) + @mock.patch('httpx.get', side_effect=mocked_requests_get) def test_mocked_requests_get(self, mock_get: mock.MagicMock): """Tests if our mocked_requests_get is returning what it should.""" success_data = mock_get(HomeView.github_api) @@ -98,7 +98,7 @@ class TestRepositoryMetadataHelpers(TestCase): self.assertIsNotNone(success_data.json_data) self.assertIsNone(fail_data.json_data) - @mock.patch('requests.get') + @mock.patch('httpx.get') def test_falls_back_to_database_on_error(self, mock_get: mock.MagicMock): """Tests that fallback to the database is performed when we get garbage back.""" repo_data = RepositoryMetadata( @@ -117,13 +117,16 @@ class TestRepositoryMetadataHelpers(TestCase): [item] = metadata self.assertEqual(item, repo_data) - @mock.patch('requests.get') + @mock.patch('httpx.get') def test_falls_back_to_database_on_error_without_entries(self, mock_get: mock.MagicMock): """Tests that fallback to the database is performed when we get garbage back.""" mock_get.return_value.json.return_value = ['garbage'] - metadata = self.home_view._get_repo_data() - self.assertEquals(len(metadata), 0) + # Capture logs and ensure the problematic response is logged + with self.assertLogs(): + metadata = self.home_view._get_repo_data() + + self.assertEqual(len(metadata), 0) def test_cleans_up_stale_metadata(self): """Tests that we clean up stale metadata when we start the HomeView.""" diff --git a/pydis_site/apps/home/tests/test_views.py b/pydis_site/apps/home/tests/test_views.py index b1215df4..379b984e 100644 --- a/pydis_site/apps/home/tests/test_views.py +++ b/pydis_site/apps/home/tests/test_views.py @@ -1,3 +1,5 @@ +from unittest import mock + from django.test import TestCase from django.urls import reverse @@ -6,5 +8,6 @@ class TestIndexReturns200(TestCase): def test_index_returns_200(self): """Check that the index page returns a HTTP 200 response.""" url = reverse('home:home') - resp = self.client.get(url) + with mock.patch("pydis_site.apps.home.views.HomeView._get_api_data", autospec=True): + resp = self.client.get(url) self.assertEqual(resp.status_code, 200) diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views.py index e28a3a00..bfa9e02d 100644 --- a/pydis_site/apps/home/views/home.py +++ b/pydis_site/apps/home/views.py @@ -1,7 +1,6 @@ import logging -from typing import Dict, List -import requests +import httpx from django.core.handlers.wsgi import WSGIRequest from django.http import HttpResponse from django.shortcuts import render @@ -10,7 +9,6 @@ from django.views import View from pydis_site import settings from pydis_site.apps.home.models import RepositoryMetadata -from pydis_site.constants import GITHUB_TOKEN, TIMEOUT_PERIOD log = logging.getLogger(__name__) @@ -33,9 +31,7 @@ class HomeView(View): def __init__(self): """Clean up stale RepositoryMetadata.""" - self._static_build = settings.env("STATIC_BUILD") - - if not self._static_build: + if not settings.STATIC_BUILD: RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete() # If no token is defined (for example in local development), then @@ -43,12 +39,12 @@ class HomeView(View): # specifically, GitHub will reject any requests from us due to the # invalid header. We can make a limited number of anonymous requests # though, which is useful for testing. - if GITHUB_TOKEN: - self.headers = {"Authorization": f"token {GITHUB_TOKEN}"} + if settings.GITHUB_TOKEN: + self.headers = {"Authorization": f"token {settings.GITHUB_TOKEN}"} else: self.headers = {} - def _get_api_data(self) -> Dict[str, Dict[str, str]]: + def _get_api_data(self) -> dict[str, dict[str, str]]: """ Call the GitHub API and get information about our repos. @@ -57,12 +53,12 @@ class HomeView(View): repo_dict = {} try: # Fetch the data from the GitHub API - api_data: List[dict] = requests.get( + api_data: list[dict] = httpx.get( self.github_api, headers=self.headers, - timeout=TIMEOUT_PERIOD + timeout=settings.TIMEOUT_PERIOD ).json() - except requests.exceptions.Timeout: + except httpx.TimeoutException: log.error("Request to fetch GitHub repository metadata for timed out!") return repo_dict @@ -92,10 +88,10 @@ class HomeView(View): return repo_dict - def _get_repo_data(self) -> List[RepositoryMetadata]: + def _get_repo_data(self) -> list[RepositoryMetadata]: """Build a list of RepositoryMetadata objects that we can use to populate the front page.""" # First off, load the timestamp of the least recently updated entry. - if self._static_build: + if settings.STATIC_BUILD: last_update = None else: last_update = ( @@ -122,10 +118,9 @@ class HomeView(View): for api_data in api_repositories.values() ] - if settings.env("STATIC_BUILD"): + if settings.STATIC_BUILD: return data - else: - return RepositoryMetadata.objects.bulk_create(data) + return RepositoryMetadata.objects.bulk_create(data) # If the data is stale, we should refresh it. if (timezone.now() - last_update).seconds > self.repository_cache_ttl: @@ -152,8 +147,7 @@ class HomeView(View): return database_repositories # Otherwise, if the data is fresher than 2 minutes old, we should just return it. - else: - return RepositoryMetadata.objects.all() + return RepositoryMetadata.objects.all() def get(self, request: WSGIRequest) -> HttpResponse: """Collect repo data and render the homepage view.""" diff --git a/pydis_site/apps/home/views/__init__.py b/pydis_site/apps/home/views/__init__.py deleted file mode 100644 index 28cc4d65..00000000 --- a/pydis_site/apps/home/views/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .home import HomeView, timeline - -__all__ = ["HomeView", "timeline"] |