aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/home/views/home.py
blob: e4daf3805812248b67be8e8d600bacece793f442 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from typing import Dict, List

import requests
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse
from django.shortcuts import render
from django.utils import timezone
from django.views import View

from pydis_site.apps.home.models import RepositoryMetadata


class HomeView(View):
    """The main landing page for the website."""

    github_api = "https://api.github.com/users/python-discord/repos"
    repository_cache_ttl = 600

    # Which of our GitHub repos should be displayed on the front page, and in which order?
    repos = [
        "python-discord/site",
        "python-discord/bot",
        "python-discord/snekbox",
        "python-discord/seasonalbot",
        "python-discord/django-simple-bulma",
        "python-discord/django-crispy-bulma",
    ]

    def _get_api_data(self) -> Dict[str, Dict[str, str]]:
        """Call the GitHub API and get information about our repos."""

        repo_dict = {repo_name: {} for repo_name in self.repos}

        # Fetch the data from the GitHub API
        api_data = requests.get(self.github_api)
        api_data = api_data.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"],
                }
        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")

            # If the data is stale, we should refresh it.
            if (timezone.now() - repo_data.last_updated).seconds > self.repository_cache_ttl:

                # Get new data from API
                api_repositories = self._get_api_data()
                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 this is raised, the database has no repodata at all, we will create them all.
        except RepositoryMetadata.DoesNotExist:

            # Get new data from API
            api_repositories = self._get_api_data()
            database_repositories = []

            # 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"],
                )
                repo_data.save()
                database_repositories.append(repo_data)

            return database_repositories

    def get(self, request: WSGIRequest) -> HttpResponse:
        """Collect repo data and render the homepage view"""

        repo_data = self._get_repo_data()
        return render(request, "home/index.html", {"repo_data": repo_data})