aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/home
diff options
context:
space:
mode:
authorGravatar hedy <[email protected]>2023-12-14 20:28:17 +0800
committerGravatar hedy <[email protected]>2023-12-14 20:28:17 +0800
commit449c08fd5459b2f804dbf825086ec1dd0f244d8a (patch)
treee4589cb227cdb2e611bcbf9b02ea481fe24cdb34 /pydis_site/apps/home
parentResize theme switch (diff)
parentMerge 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.md35
-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__.py3
-rw-r--r--pydis_site/apps/home/tests/test_repodata_helpers.py25
-rw-r--r--pydis_site/apps/home/tests/test_views.py5
-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__.py3
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"]