diff options
| -rw-r--r-- | pydis_site/apps/home/tests/test_repodata_helpers.py | 8 | ||||
| -rw-r--r-- | pydis_site/apps/home/views/home.py | 147 | ||||
| -rw-r--r-- | pydis_site/templates/home/index.html | 98 | 
3 files changed, 127 insertions, 126 deletions
| diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py index 77b1a68d..34bbdcde 100644 --- a/pydis_site/apps/home/tests/test_repodata_helpers.py +++ b/pydis_site/apps/home/tests/test_repodata_helpers.py @@ -123,10 +123,4 @@ class TestRepositoryMetadataHelpers(TestCase):          mock_get.return_value.json.return_value = ['garbage']          metadata = self.home_view._get_repo_data() -        self.assertEquals(len(metadata), len(self.home_view.repos)) -        for item in metadata: -            with self.subTest(item=item): -                self.assertEqual(item.description, "Not available.") -                self.assertEqual(item.forks, 999) -                self.assertEqual(item.stargazers, 999) -                self.assertEqual(item.language, "Python") +        self.assertEquals(len(metadata), 0) diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py index c1c2055c..97253a0c 100644 --- a/pydis_site/apps/home/views/home.py +++ b/pydis_site/apps/home/views/home.py @@ -1,4 +1,4 @@ -import datetime +import logging  from typing import Dict, List  import requests @@ -10,6 +10,8 @@ from django.views import View  from pydis_site.apps.home.models import RepositoryMetadata +log = logging.getLogger(__name__) +  class HomeView(View):      """The main landing page for the website.""" @@ -28,76 +30,88 @@ class HomeView(View):      ]      def _get_api_data(self) -> Dict[str, Dict[str, str]]: -        """Call the GitHub API and get information about our repos.""" -        repo_dict: Dict[str, dict] = {repo_name: {} for repo_name in self.repos} +        """ +        Call the GitHub API and get information about our repos. + +        If we're unable to get that info for any reason, return an empty dict. +        """ +        repo_dict = {}          # Fetch the data from the GitHub API          api_data: List[dict] = requests.get(self.github_api).json()          # Process the API data into our dict          for repo in api_data: -            full_name = repo["full_name"] - -            if full_name in self.repos: -                repo_dict[full_name] = { -                    "full_name": repo["full_name"], -                    "description": repo["description"], -                    "language": repo["language"], -                    "forks_count": repo["forks_count"], -                    "stargazers_count": repo["stargazers_count"], -                } +            try: +                full_name = repo["full_name"] + +                if full_name in self.repos: +                    repo_dict[full_name] = { +                        "full_name": repo["full_name"], +                        "description": repo["description"], +                        "language": repo["language"], +                        "forks_count": repo["forks_count"], +                        "stargazers_count": repo["stargazers_count"], +                    } +            # Something is not right about the API data we got back from GitHub. +            except (TypeError, ConnectionError, KeyError) as e: +                log.error( +                    "Unable to parse the GitHub repository metadata from response!", +                    extra={ +                        'api_data': api_data, +                        'error': e +                    } +                ) +                continue          return repo_dict      def _get_repo_data(self) -> List[RepositoryMetadata]:          """Build a list of RepositoryMetadata objects that we can use to populate the front page.""" -        # Try to get site data from the cache -        try: -            repo_data = RepositoryMetadata.objects.get(repo_name="python-discord/site") +        database_repositories = [] -            # If the data is stale, we should refresh it. -            if (timezone.now() - repo_data.last_updated).seconds > self.repository_cache_ttl: +        # First, let's see if we have any metadata cached. +        cached_data = RepositoryMetadata.objects.all() -                # Try to get new data from the API. If it fails, return the cached data. -                try: -                    api_repositories = self._get_api_data() -                except (TypeError, ConnectionError): -                    return RepositoryMetadata.objects.all() -                database_repositories = [] - -                # Update or create all RepoData objects in self.repos -                for repo_name, api_data in api_repositories.items(): -                    try: -                        repo_data = RepositoryMetadata.objects.get(repo_name=repo_name) -                        repo_data.description = api_data["description"] -                        repo_data.language = api_data["language"] -                        repo_data.forks = api_data["forks_count"] -                        repo_data.stargazers = api_data["stargazers_count"] -                    except RepositoryMetadata.DoesNotExist: -                        repo_data = RepositoryMetadata( -                            repo_name=api_data["full_name"], -                            description=api_data["description"], -                            forks=api_data["forks_count"], -                            stargazers=api_data["stargazers_count"], -                            language=api_data["language"], -                        ) -                    repo_data.save() -                    database_repositories.append(repo_data) -                return database_repositories - -            # Otherwise, if the data is fresher than 2 minutes old, we should just return it. -            else: -                return RepositoryMetadata.objects.all() +        # If we don't, we have to create some! +        if not cached_data: -        # If this is raised, the database has no repodata at all, we will create them all. -        except RepositoryMetadata.DoesNotExist: -            database_repositories = [] -            try: -                # Get new data from API -                api_repositories = self._get_api_data() +            # Try to get new data from the API. If it fails, we'll return an empty list. +            # In this case, we simply don't display our projects on the site. +            api_repositories = self._get_api_data() + +            # Create all the repodata records in the database. +            for api_data in api_repositories.values(): +                repo_data = RepositoryMetadata( +                    repo_name=api_data["full_name"], +                    description=api_data["description"], +                    forks=api_data["forks_count"], +                    stargazers=api_data["stargazers_count"], +                    language=api_data["language"], +                ) -                # Create all the repodata records in the database. -                for api_data in api_repositories.values(): +                repo_data.save() +                database_repositories.append(repo_data) + +            return database_repositories + +        # If the data is stale, we should refresh it. +        if (timezone.now() - cached_data[0].last_updated).seconds > self.repository_cache_ttl: +            # Try to get new data from the API. If it fails, return the cached data. +            api_repositories = self._get_api_data() + +            if not api_repositories: +                return RepositoryMetadata.objects.all() + +            # Update or create all RepoData objects in self.repos +            for repo_name, api_data in api_repositories.items(): +                try: +                    repo_data = RepositoryMetadata.objects.get(repo_name=repo_name) +                    repo_data.description = api_data["description"] +                    repo_data.language = api_data["language"] +                    repo_data.forks = api_data["forks_count"] +                    repo_data.stargazers = api_data["stargazers_count"] +                except RepositoryMetadata.DoesNotExist:                      repo_data = RepositoryMetadata(                          repo_name=api_data["full_name"],                          description=api_data["description"], @@ -105,23 +119,14 @@ class HomeView(View):                          stargazers=api_data["stargazers_count"],                          language=api_data["language"],                      ) -                    repo_data.save() -                    database_repositories.append(repo_data) -            except TypeError: -                for repo_name in self.repos: -                    repo_data = RepositoryMetadata( -                        last_updated=timezone.now() - datetime.timedelta(minutes=50), -                        repo_name=repo_name, -                        description="Not available.", -                        forks=999, -                        stargazers=999, -                        language="Python", -                    ) -                    repo_data.save() -                    database_repositories.append(repo_data) - +                repo_data.save() +                database_repositories.append(repo_data)              return database_repositories +        # Otherwise, if the data is fresher than 2 minutes old, we should just return it. +        else: +            return RepositoryMetadata.objects.all() +      def get(self, request: WSGIRequest) -> HttpResponse:          """Collect repo data and render the homepage view."""          repo_data = self._get_repo_data() diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html index 72a5f67c..a98613a3 100644 --- a/pydis_site/templates/home/index.html +++ b/pydis_site/templates/home/index.html @@ -130,57 +130,59 @@    </section>    <!-- Projects --> -  <section id="projects" class="section"> -    <div class="container"> -      <h1 class="is-size-1">Projects</h1> - -      <div class="columns is-multiline is-tablet"> - -        {# Generate project data from HomeView.repos #} -        {% for repo in repo_data %} -          <div class="column is-one-third-desktop is-half-tablet"> - -            <a href="https://github.com/{{ repo.repo_name }}"> -              <article class="card"> - -                <header class="card-header"> -                  <span class="card-header-icon"> -                    <span class="icon"><i class="fab fa-github"></i></span> -                  </span> -                  <div class="card-header-title"> -                    {{ repo.repo_name|cut:"python-discord/" }} -                  </div> -                </header> - -                <p class="card-content"> -                  {{ repo.description }} -                </p> - -                <footer class="card-footer"> -                  <div class="card-footer-item"> -                    <i class="repo-language-dot {{ repo.language | lower }}"></i> -                    {{ repo.language }} -                  </div> -                  <div class="card-footer-item"> -                    <i class="fas fa-star"></i> -                    {{ repo.stargazers }} -                  </div> -                  <div class="card-footer-item"> -                    <i class="fas fa-code-branch"></i> -                    {{ repo.forks }} -                  </div> -                </footer> - -              </article> -            </a> +  {%  if repo_data %} +    <section id="projects" class="section"> +      <div class="container"> +        <h1 class="is-size-1">Projects</h1> + +        <div class="columns is-multiline is-tablet"> + +          {# Generate project data from HomeView.repos #} +          {% for repo in repo_data %} +            <div class="column is-one-third-desktop is-half-tablet"> + +              <a href="https://github.com/{{ repo.repo_name }}"> +                <article class="card"> + +                  <header class="card-header"> +                    <span class="card-header-icon"> +                      <span class="icon"><i class="fab fa-github"></i></span> +                    </span> +                    <div class="card-header-title"> +                      {{ repo.repo_name|cut:"python-discord/" }} +                    </div> +                  </header> + +                  <p class="card-content"> +                    {{ repo.description }} +                  </p> + +                  <footer class="card-footer"> +                    <div class="card-footer-item"> +                      <i class="repo-language-dot {{ repo.language | lower }}"></i> +                      {{ repo.language }} +                    </div> +                    <div class="card-footer-item"> +                      <i class="fas fa-star"></i> +                      {{ repo.stargazers }} +                    </div> +                    <div class="card-footer-item"> +                      <i class="fas fa-code-branch"></i> +                      {{ repo.forks }} +                    </div> +                  </footer> + +                </article> +              </a> -          </div> -        {% endfor %} +            </div> +          {% endfor %} -      </div> +        </div> -    </div> -  </section> +      </div> +    </section> +  {% endif %}    <!-- Sponsors -->    <section id="sponsors" class="hero is-light"> | 
