diff options
| -rw-r--r-- | pydis_site/apps/resources/apps.py | 92 | ||||
| -rw-r--r-- | pydis_site/apps/resources/tests/test_resource_data.py | 2 | ||||
| -rw-r--r-- | pydis_site/apps/resources/views.py | 103 | 
3 files changed, 102 insertions, 95 deletions
| diff --git a/pydis_site/apps/resources/apps.py b/pydis_site/apps/resources/apps.py index 93117654..51cb064b 100644 --- a/pydis_site/apps/resources/apps.py +++ b/pydis_site/apps/resources/apps.py @@ -1,7 +1,99 @@ +from pathlib import Path + +import yaml  from django.apps import AppConfig +from pydis_site import settings +from pydis_site.apps.resources.templatetags.to_kebabcase import to_kebabcase + +RESOURCES_PATH = Path(settings.BASE_DIR, "pydis_site", "apps", "resources", "resources") +  class ResourcesConfig(AppConfig):      """AppConfig instance for Resources app."""      name = 'pydis_site.apps.resources' + +    @staticmethod +    def _sort_key_disregard_the(tuple_: tuple) -> str: +        """Sort a tuple by its key alphabetically, disregarding 'the' as a prefix.""" +        name, resource = tuple_ +        name = name.casefold() +        if name.startswith(("the ", "the_")): +            return name[4:] +        return name + + +    def ready(self) -> None: +        """Set up all the resources.""" +        # Load the resources from the yaml files in /resources/ +        self.resources = { +            path.stem: yaml.safe_load(path.read_text()) +            for path in RESOURCES_PATH.rglob("*.yaml") +        } + +        # Sort the resources alphabetically +        self.resources = dict(sorted(self.resources.items(), key=self._sort_key_disregard_the)) + +        # Parse out all current tags +        resource_tags = { +            "topics": set(), +            "payment_tiers": set(), +            "difficulty": set(), +            "type": set(), +        } +        for resource_name, resource in self.resources.items(): +            css_classes = [] +            for tag_type in resource_tags: +                # Store the tags into `resource_tags` +                tags = resource.get("tags", {}).get(tag_type, []) +                for tag in tags: +                    tag = tag.title() +                    tag = tag.replace("And", "and") +                    resource_tags[tag_type].add(tag) + +                # Make a CSS class friendly representation too, while we're already iterating. +                for tag in tags: +                    css_tag = to_kebabcase(f"{tag_type}-{tag}") +                    css_classes.append(css_tag) + +            # Now add the css classes back to the resource, so we can use them in the template. +            self.resources[resource_name]["css_classes"] = " ".join(css_classes) + +        # Set up all the filter checkbox metadata +        self.filters = { +            "Difficulty": { +                "filters": sorted(resource_tags.get("difficulty")), +                "icon": "fas fa-brain", +                "hidden": False, +            }, +            "Type": { +                "filters": sorted(resource_tags.get("type")), +                "icon": "fas fa-photo-video", +                "hidden": False, +            }, +            "Payment tiers": { +                "filters": sorted(resource_tags.get("payment_tiers")), +                "icon": "fas fa-dollar-sign", +                "hidden": True, +            }, +            "Topics": { +                "filters": sorted(resource_tags.get("topics")), +                "icon": "fas fa-lightbulb", +                "hidden": True, +            } +        } + +        # The bottom topic should always be "Other". +        self.filters["Topics"]["filters"].remove("Other") +        self.filters["Topics"]["filters"].append("Other") + +        # A complete list of valid filter names +        self.valid_filters = { +            "topics": [to_kebabcase(topic) for topic in self.filters["Topics"]["filters"]], +            "payment_tiers": [ +                to_kebabcase(tier) for tier in self.filters["Payment tiers"]["filters"] +            ], +            "type": [to_kebabcase(type_) for type_ in self.filters["Type"]["filters"]], +            "difficulty": [to_kebabcase(tier) for tier in self.filters["Difficulty"]["filters"]], +        } diff --git a/pydis_site/apps/resources/tests/test_resource_data.py b/pydis_site/apps/resources/tests/test_resource_data.py index 3a96e8b9..d96d840e 100644 --- a/pydis_site/apps/resources/tests/test_resource_data.py +++ b/pydis_site/apps/resources/tests/test_resource_data.py @@ -1,7 +1,7 @@  import yaml  from django.test import TestCase -from pydis_site.apps.resources.views import RESOURCES_PATH +from pydis_site.apps.resources.apps import RESOURCES_PATH  class TestResourceData(TestCase): diff --git a/pydis_site/apps/resources/views.py b/pydis_site/apps/resources/views.py index a2cd8d0c..3632b2e2 100644 --- a/pydis_site/apps/resources/views.py +++ b/pydis_site/apps/resources/views.py @@ -1,114 +1,29 @@  import json -from pathlib import Path -import yaml +from django.apps import apps  from django.core.handlers.wsgi import WSGIRequest  from django.http import HttpResponse, HttpResponseNotFound  from django.shortcuts import render  from django.views import View -from pydis_site import settings -from pydis_site.apps.resources.templatetags.to_kebabcase import to_kebabcase -RESOURCES_PATH = Path(settings.BASE_DIR, "pydis_site", "apps", "resources", "resources") +APP_NAME = "resources"  class ResourceView(View):      """Our curated list of good learning resources.""" -    @staticmethod -    def _sort_key_disregard_the(tuple_: tuple) -> str: -        """Sort a tuple by its key alphabetically, disregarding 'the' as a prefix.""" -        name, resource = tuple_ -        name = name.casefold() -        if name.startswith(("the ", "the_")): -            return name[4:] -        return name - -    def __init__(self, *args, **kwargs): -        """Set up all the resources.""" -        super().__init__(*args, **kwargs) - -        # Load the resources from the yaml files in /resources/ -        self.resources = { -            path.stem: yaml.safe_load(path.read_text()) -            for path in RESOURCES_PATH.rglob("*.yaml") -        } - -        # Sort the resources alphabetically -        self.resources = dict(sorted(self.resources.items(), key=self._sort_key_disregard_the)) - -        # Parse out all current tags -        resource_tags = { -            "topics": set(), -            "payment_tiers": set(), -            "difficulty": set(), -            "type": set(), -        } -        for resource_name, resource in self.resources.items(): -            css_classes = [] -            for tag_type in resource_tags: -                # Store the tags into `resource_tags` -                tags = resource.get("tags", {}).get(tag_type, []) -                for tag in tags: -                    tag = tag.title() -                    tag = tag.replace("And", "and") -                    resource_tags[tag_type].add(tag) - -                # Make a CSS class friendly representation too, while we're already iterating. -                for tag in tags: -                    css_tag = to_kebabcase(f"{tag_type}-{tag}") -                    css_classes.append(css_tag) - -            # Now add the css classes back to the resource, so we can use them in the template. -            self.resources[resource_name]["css_classes"] = " ".join(css_classes) - -        # Set up all the filter checkbox metadata -        self.filters = { -            "Difficulty": { -                "filters": sorted(resource_tags.get("difficulty")), -                "icon": "fas fa-brain", -                "hidden": False, -            }, -            "Type": { -                "filters": sorted(resource_tags.get("type")), -                "icon": "fas fa-photo-video", -                "hidden": False, -            }, -            "Payment tiers": { -                "filters": sorted(resource_tags.get("payment_tiers")), -                "icon": "fas fa-dollar-sign", -                "hidden": True, -            }, -            "Topics": { -                "filters": sorted(resource_tags.get("topics")), -                "icon": "fas fa-lightbulb", -                "hidden": True, -            } -        } - -        # The bottom topic should always be "Other". -        self.filters["Topics"]["filters"].remove("Other") -        self.filters["Topics"]["filters"].append("Other") - -        # A complete list of valid filter names -        self.valid_filters = { -            "topics": [to_kebabcase(topic) for topic in self.filters["Topics"]["filters"]], -            "payment_tiers": [ -                to_kebabcase(tier) for tier in self.filters["Payment tiers"]["filters"] -            ], -            "type": [to_kebabcase(type_) for type_ in self.filters["Type"]["filters"]], -            "difficulty": [to_kebabcase(tier) for tier in self.filters["Difficulty"]["filters"]], -        } -      def get(self, request: WSGIRequest, resource_type: str | None = None) -> HttpResponse:          """List out all the resources, and any filtering options from the URL."""          # Add type filtering if the request is made to somewhere like /resources/video.          # We also convert all spaces to dashes, so they'll correspond with the filters. + +        app = apps.get_app_config(APP_NAME) +          if resource_type:              dashless_resource_type = resource_type.replace("-", " ") -            if dashless_resource_type.title() not in self.filters["Type"]["filters"]: +            if dashless_resource_type.title() not in app.filters["Type"]["filters"]:                  return HttpResponseNotFound()              resource_type = resource_type.replace(" ", "-") @@ -117,9 +32,9 @@ class ResourceView(View):              request,              template_name="resources/resources.html",              context={ -                "resources": self.resources, -                "filters": self.filters, -                "valid_filters": json.dumps(self.valid_filters), +                "resources": app.resources, +                "filters": app.filters, +                "valid_filters": json.dumps(app.valid_filters),                  "resource_type": resource_type,              }          ) | 
