prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Unable to parse the GitHub repository metadata from response!
  Sentry Issue: [SITE-P](https://sentry.io/organizations/python-discord/issues/2093966668/?referrer=github_integration)
  
  ```
  Unable to parse the GitHub repository metadata from response!
  ```
  
  This is caused by us hitting github ratelimits, as we're not authenticating with the API.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pydis_site/constants.py`
  Content:
  ```
  1 import os
  2 
  3 GIT_SHA = os.environ.get("GIT_SHA", "development")
  4
  ```
  
  Path: `pydis_site/apps/home/views/home.py`
  Content:
  ```
  1 import logging
  2 from typing import Dict, List
  3 
  4 import requests
  5 from django.core.handlers.wsgi import WSGIRequest
  6 from django.http import HttpResponse
  7 from django.shortcuts import render
  8 from django.utils import timezone
  9 from django.views import View
  10 
  11 from pydis_site.apps.home.models import RepositoryMetadata
  12 
  13 log = logging.getLogger(__name__)
  14 
  15 
  16 class HomeView(View):
  17     """The main landing page for the website."""
  18 
  19     github_api = "https://api.github.com/users/python-discord/repos?per_page=100"
  20     repository_cache_ttl = 3600
  21 
  22     # Which of our GitHub repos should be displayed on the front page, and in which order?
  23     repos = [
  24         "python-discord/site",
  25         "python-discord/bot",
  26         "python-discord/snekbox",
  27         "python-discord/sir-lancebot",
  28         "python-discord/metricity",
  29         "python-discord/django-simple-bulma",
  30     ]
  31 
  32     def __init__(self):
  33         """Clean up stale RepositoryMetadata."""
  34         RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()
  35 
  36     def _get_api_data(self) -> Dict[str, Dict[str, str]]:
  37         """
  38         Call the GitHub API and get information about our repos.
  39 
  40         If we're unable to get that info for any reason, return an empty dict.
  41         """
  42         repo_dict = {}
  43 
  44         # Fetch the data from the GitHub API
  45         api_data: List[dict] = requests.get(self.github_api).json()
  46 
  47         # Process the API data into our dict
  48         for repo in api_data:
  49             try:
  50                 full_name = repo["full_name"]
  51 
  52                 if full_name in self.repos:
  53                     repo_dict[full_name] = {
  54                         "full_name": repo["full_name"],
  55                         "description": repo["description"],
  56                         "language": repo["language"],
  57                         "forks_count": repo["forks_count"],
  58                         "stargazers_count": repo["stargazers_count"],
  59                     }
  60             # Something is not right about the API data we got back from GitHub.
  61             except (TypeError, ConnectionError, KeyError) as e:
  62                 log.error(
  63                     "Unable to parse the GitHub repository metadata from response!",
  64                     extra={
  65                         'api_data': api_data,
  66                         'error': e
  67                     }
  68                 )
  69                 continue
  70 
  71         return repo_dict
  72 
  73     def _get_repo_data(self) -> List[RepositoryMetadata]:
  74         """Build a list of RepositoryMetadata objects that we can use to populate the front page."""
  75         database_repositories = []
  76 
  77         # First, let's see if we have any metadata cached.
  78         cached_data = RepositoryMetadata.objects.all()
  79 
  80         # If we don't, we have to create some!
  81         if not cached_data:
  82 
  83             # Try to get new data from the API. If it fails, we'll return an empty list.
  84             # In this case, we simply don't display our projects on the site.
  85             api_repositories = self._get_api_data()
  86 
  87             # Create all the repodata records in the database.
  88             for api_data in api_repositories.values():
  89                 repo_data = RepositoryMetadata(
  90                     repo_name=api_data["full_name"],
  91                     description=api_data["description"],
  92                     forks=api_data["forks_count"],
  93                     stargazers=api_data["stargazers_count"],
  94                     language=api_data["language"],
  95                 )
  96 
  97                 repo_data.save()
  98                 database_repositories.append(repo_data)
  99 
  100             return database_repositories
  101 
  102         # If the data is stale, we should refresh it.
  103         if (timezone.now() - cached_data[0].last_updated).seconds > self.repository_cache_ttl:
  104             # Try to get new data from the API. If it fails, return the cached data.
  105             api_repositories = self._get_api_data()
  106 
  107             if not api_repositories:
  108                 return RepositoryMetadata.objects.all()
  109 
  110             # Update or create all RepoData objects in self.repos
  111             for repo_name, api_data in api_repositories.items():
  112                 try:
  113                     repo_data = RepositoryMetadata.objects.get(repo_name=repo_name)
  114                     repo_data.description = api_data["description"]
  115                     repo_data.language = api_data["language"]
  116                     repo_data.forks = api_data["forks_count"]
  117                     repo_data.stargazers = api_data["stargazers_count"]
  118                 except RepositoryMetadata.DoesNotExist:
  119                     repo_data = RepositoryMetadata(
  120                         repo_name=api_data["full_name"],
  121                         description=api_data["description"],
  122                         forks=api_data["forks_count"],
  123                         stargazers=api_data["stargazers_count"],
  124                         language=api_data["language"],
  125                     )
  126                 repo_data.save()
  127                 database_repositories.append(repo_data)
  128             return database_repositories
  129 
  130         # Otherwise, if the data is fresher than 2 minutes old, we should just return it.
  131         else:
  132             return RepositoryMetadata.objects.all()
  133 
  134     def get(self, request: WSGIRequest) -> HttpResponse:
  135         """Collect repo data and render the homepage view."""
  136         repo_data = self._get_repo_data()
  137         return render(request, "home/index.html", {"repo_data": repo_data})
  138 
  139 
  140 def timeline(request: WSGIRequest) -> HttpResponse:
  141     """Render timeline view."""
  142     return render(request, 'home/timeline.html')
  143
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py
  --- a/pydis_site/apps/home/views/home.py
  +++ b/pydis_site/apps/home/views/home.py
  @@ -9,6 +9,7 @@
   from django.views import View
   
   from pydis_site.apps.home.models import RepositoryMetadata
  +from pydis_site.constants import GITHUB_TOKEN
   
   log = logging.getLogger(__name__)
   
  @@ -18,6 +19,7 @@
   
       github_api = "https://api.github.com/users/python-discord/repos?per_page=100"
       repository_cache_ttl = 3600
  +    headers = {"Authorization": f"token {GITHUB_TOKEN}"}
   
       # Which of our GitHub repos should be displayed on the front page, and in which order?
       repos = [
  @@ -42,7 +44,7 @@
           repo_dict = {}
   
           # Fetch the data from the GitHub API
  -        api_data: List[dict] = requests.get(self.github_api).json()
  +        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()
   
           # Process the API data into our dict
           for repo in api_data:
  diff --git a/pydis_site/constants.py b/pydis_site/constants.py
  --- a/pydis_site/constants.py
  +++ b/pydis_site/constants.py
  @@ -1,3 +1,4 @@
   import os
   
   GIT_SHA = os.environ.get("GIT_SHA", "development")
  +GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
  
verification_info: {"golden_diff": "diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py\n--- a/pydis_site/apps/home/views/home.py\n+++ b/pydis_site/apps/home/views/home.py\n@@ -9,6 +9,7 @@\n from django.views import View\n \n from pydis_site.apps.home.models import RepositoryMetadata\n+from pydis_site.constants import GITHUB_TOKEN\n \n log = logging.getLogger(__name__)\n \n@@ -18,6 +19,7 @@\n \n     github_api = \"https://api.github.com/users/python-discord/repos?per_page=100\"\n     repository_cache_ttl = 3600\n+    headers = {\"Authorization\": f\"token {GITHUB_TOKEN}\"}\n \n     # Which of our GitHub repos should be displayed on the front page, and in which order?\n     repos = [\n@@ -42,7 +44,7 @@\n         repo_dict = {}\n \n         # Fetch the data from the GitHub API\n-        api_data: List[dict] = requests.get(self.github_api).json()\n+        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()\n \n         # Process the API data into our dict\n         for repo in api_data:\ndiff --git a/pydis_site/constants.py b/pydis_site/constants.py\n--- a/pydis_site/constants.py\n+++ b/pydis_site/constants.py\n@@ -1,3 +1,4 @@\n import os\n \n GIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\n+GITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\")\n", "issue": "Unable to parse the GitHub repository metadata from response!\nSentry Issue: [SITE-P](https://sentry.io/organizations/python-discord/issues/2093966668/?referrer=github_integration)\n\n```\nUnable to parse the GitHub repository metadata from response!\n```\n\nThis is caused by us hitting github ratelimits, as we're not authenticating with the API.\n", "before_files": [{"content": "import os\n\nGIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\n", "path": "pydis_site/constants.py"}, {"content": "import logging\nfrom typing import Dict, List\n\nimport requests\nfrom django.core.handlers.wsgi import WSGIRequest\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\nfrom django.utils import timezone\nfrom django.views import View\n\nfrom pydis_site.apps.home.models import RepositoryMetadata\n\nlog = logging.getLogger(__name__)\n\n\nclass HomeView(View):\n    \"\"\"The main landing page for the website.\"\"\"\n\n    github_api = \"https://api.github.com/users/python-discord/repos?per_page=100\"\n    repository_cache_ttl = 3600\n\n    # Which of our GitHub repos should be displayed on the front page, and in which order?\n    repos = [\n        \"python-discord/site\",\n        \"python-discord/bot\",\n        \"python-discord/snekbox\",\n        \"python-discord/sir-lancebot\",\n        \"python-discord/metricity\",\n        \"python-discord/django-simple-bulma\",\n    ]\n\n    def __init__(self):\n        \"\"\"Clean up stale RepositoryMetadata.\"\"\"\n        RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()\n\n    def _get_api_data(self) -> Dict[str, Dict[str, str]]:\n        \"\"\"\n        Call the GitHub API and get information about our repos.\n\n        If we're unable to get that info for any reason, return an empty dict.\n        \"\"\"\n        repo_dict = {}\n\n        # Fetch the data from the GitHub API\n        api_data: List[dict] = requests.get(self.github_api).json()\n\n        # Process the API data into our dict\n        for repo in api_data:\n            try:\n                full_name = repo[\"full_name\"]\n\n                if full_name in self.repos:\n                    repo_dict[full_name] = {\n                        \"full_name\": repo[\"full_name\"],\n                        \"description\": repo[\"description\"],\n                        \"language\": repo[\"language\"],\n                        \"forks_count\": repo[\"forks_count\"],\n                        \"stargazers_count\": repo[\"stargazers_count\"],\n                    }\n            # Something is not right about the API data we got back from GitHub.\n            except (TypeError, ConnectionError, KeyError) as e:\n                log.error(\n                    \"Unable to parse the GitHub repository metadata from response!\",\n                    extra={\n                        'api_data': api_data,\n                        'error': e\n                    }\n                )\n                continue\n\n        return repo_dict\n\n    def _get_repo_data(self) -> List[RepositoryMetadata]:\n        \"\"\"Build a list of RepositoryMetadata objects that we can use to populate the front page.\"\"\"\n        database_repositories = []\n\n        # First, let's see if we have any metadata cached.\n        cached_data = RepositoryMetadata.objects.all()\n\n        # If we don't, we have to create some!\n        if not cached_data:\n\n            # Try to get new data from the API. If it fails, we'll return an empty list.\n            # In this case, we simply don't display our projects on the site.\n            api_repositories = self._get_api_data()\n\n            # Create all the repodata records in the database.\n            for api_data in api_repositories.values():\n                repo_data = RepositoryMetadata(\n                    repo_name=api_data[\"full_name\"],\n                    description=api_data[\"description\"],\n                    forks=api_data[\"forks_count\"],\n                    stargazers=api_data[\"stargazers_count\"],\n                    language=api_data[\"language\"],\n                )\n\n                repo_data.save()\n                database_repositories.append(repo_data)\n\n            return database_repositories\n\n        # If the data is stale, we should refresh it.\n        if (timezone.now() - cached_data[0].last_updated).seconds > self.repository_cache_ttl:\n            # Try to get new data from the API. If it fails, return the cached data.\n            api_repositories = self._get_api_data()\n\n            if not api_repositories:\n                return RepositoryMetadata.objects.all()\n\n            # Update or create all RepoData objects in self.repos\n            for repo_name, api_data in api_repositories.items():\n                try:\n                    repo_data = RepositoryMetadata.objects.get(repo_name=repo_name)\n                    repo_data.description = api_data[\"description\"]\n                    repo_data.language = api_data[\"language\"]\n                    repo_data.forks = api_data[\"forks_count\"]\n                    repo_data.stargazers = api_data[\"stargazers_count\"]\n                except RepositoryMetadata.DoesNotExist:\n                    repo_data = RepositoryMetadata(\n                        repo_name=api_data[\"full_name\"],\n                        description=api_data[\"description\"],\n                        forks=api_data[\"forks_count\"],\n                        stargazers=api_data[\"stargazers_count\"],\n                        language=api_data[\"language\"],\n                    )\n                repo_data.save()\n                database_repositories.append(repo_data)\n            return database_repositories\n\n        # Otherwise, if the data is fresher than 2 minutes old, we should just return it.\n        else:\n            return RepositoryMetadata.objects.all()\n\n    def get(self, request: WSGIRequest) -> HttpResponse:\n        \"\"\"Collect repo data and render the homepage view.\"\"\"\n        repo_data = self._get_repo_data()\n        return render(request, \"home/index.html\", {\"repo_data\": repo_data})\n\n\ndef timeline(request: WSGIRequest) -> HttpResponse:\n    \"\"\"Render timeline view.\"\"\"\n    return render(request, 'home/timeline.html')\n", "path": "pydis_site/apps/home/views/home.py"}], "after_files": [{"content": "import os\n\nGIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\nGITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\")\n", "path": "pydis_site/constants.py"}, {"content": "import logging\nfrom typing import Dict, List\n\nimport requests\nfrom django.core.handlers.wsgi import WSGIRequest\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\nfrom django.utils import timezone\nfrom django.views import View\n\nfrom pydis_site.apps.home.models import RepositoryMetadata\nfrom pydis_site.constants import GITHUB_TOKEN\n\nlog = logging.getLogger(__name__)\n\n\nclass HomeView(View):\n    \"\"\"The main landing page for the website.\"\"\"\n\n    github_api = \"https://api.github.com/users/python-discord/repos?per_page=100\"\n    repository_cache_ttl = 3600\n    headers = {\"Authorization\": f\"token {GITHUB_TOKEN}\"}\n\n    # Which of our GitHub repos should be displayed on the front page, and in which order?\n    repos = [\n        \"python-discord/site\",\n        \"python-discord/bot\",\n        \"python-discord/snekbox\",\n        \"python-discord/sir-lancebot\",\n        \"python-discord/metricity\",\n        \"python-discord/django-simple-bulma\",\n    ]\n\n    def __init__(self):\n        \"\"\"Clean up stale RepositoryMetadata.\"\"\"\n        RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()\n\n    def _get_api_data(self) -> Dict[str, Dict[str, str]]:\n        \"\"\"\n        Call the GitHub API and get information about our repos.\n\n        If we're unable to get that info for any reason, return an empty dict.\n        \"\"\"\n        repo_dict = {}\n\n        # Fetch the data from the GitHub API\n        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()\n\n        # Process the API data into our dict\n        for repo in api_data:\n            try:\n                full_name = repo[\"full_name\"]\n\n                if full_name in self.repos:\n                    repo_dict[full_name] = {\n                        \"full_name\": repo[\"full_name\"],\n                        \"description\": repo[\"description\"],\n                        \"language\": repo[\"language\"],\n                        \"forks_count\": repo[\"forks_count\"],\n                        \"stargazers_count\": repo[\"stargazers_count\"],\n                    }\n            # Something is not right about the API data we got back from GitHub.\n            except (TypeError, ConnectionError, KeyError) as e:\n                log.error(\n                    \"Unable to parse the GitHub repository metadata from response!\",\n                    extra={\n                        'api_data': api_data,\n                        'error': e\n                    }\n                )\n                continue\n\n        return repo_dict\n\n    def _get_repo_data(self) -> List[RepositoryMetadata]:\n        \"\"\"Build a list of RepositoryMetadata objects that we can use to populate the front page.\"\"\"\n        database_repositories = []\n\n        # First, let's see if we have any metadata cached.\n        cached_data = RepositoryMetadata.objects.all()\n\n        # If we don't, we have to create some!\n        if not cached_data:\n\n            # Try to get new data from the API. If it fails, we'll return an empty list.\n            # In this case, we simply don't display our projects on the site.\n            api_repositories = self._get_api_data()\n\n            # Create all the repodata records in the database.\n            for api_data in api_repositories.values():\n                repo_data = RepositoryMetadata(\n                    repo_name=api_data[\"full_name\"],\n                    description=api_data[\"description\"],\n                    forks=api_data[\"forks_count\"],\n                    stargazers=api_data[\"stargazers_count\"],\n                    language=api_data[\"language\"],\n                )\n\n                repo_data.save()\n                database_repositories.append(repo_data)\n\n            return database_repositories\n\n        # If the data is stale, we should refresh it.\n        if (timezone.now() - cached_data[0].last_updated).seconds > self.repository_cache_ttl:\n            # Try to get new data from the API. If it fails, return the cached data.\n            api_repositories = self._get_api_data()\n\n            if not api_repositories:\n                return RepositoryMetadata.objects.all()\n\n            # Update or create all RepoData objects in self.repos\n            for repo_name, api_data in api_repositories.items():\n                try:\n                    repo_data = RepositoryMetadata.objects.get(repo_name=repo_name)\n                    repo_data.description = api_data[\"description\"]\n                    repo_data.language = api_data[\"language\"]\n                    repo_data.forks = api_data[\"forks_count\"]\n                    repo_data.stargazers = api_data[\"stargazers_count\"]\n                except RepositoryMetadata.DoesNotExist:\n                    repo_data = RepositoryMetadata(\n                        repo_name=api_data[\"full_name\"],\n                        description=api_data[\"description\"],\n                        forks=api_data[\"forks_count\"],\n                        stargazers=api_data[\"stargazers_count\"],\n                        language=api_data[\"language\"],\n                    )\n                repo_data.save()\n                database_repositories.append(repo_data)\n            return database_repositories\n\n        # Otherwise, if the data is fresher than 2 minutes old, we should just return it.\n        else:\n            return RepositoryMetadata.objects.all()\n\n    def get(self, request: WSGIRequest) -> HttpResponse:\n        \"\"\"Collect repo data and render the homepage view.\"\"\"\n        repo_data = self._get_repo_data()\n        return render(request, \"home/index.html\", {\"repo_data\": repo_data})\n\n\ndef timeline(request: WSGIRequest) -> HttpResponse:\n    \"\"\"Render timeline view.\"\"\"\n    return render(request, 'home/timeline.html')\n", "path": "pydis_site/apps/home/views/home.py"}]}