From 6cea8884316f3b3343cf7df6525358d2805520ac Mon Sep 17 00:00:00 2001 From: RohanJnr Date: Sun, 11 Feb 2024 12:26:39 +0530 Subject: Move resorce loading from view init() to AppConfig ready() method This is done to load the resources only once on startup instead of loading it everytime the view is initialized which is done whenever a request is made to the resources endpoint. --- pydis_site/apps/resources/apps.py | 92 +++++++++++++++++++++++++++++++++ pydis_site/apps/resources/views.py | 103 ++++--------------------------------- 2 files changed, 101 insertions(+), 94 deletions(-) (limited to 'pydis_site/apps') 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/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, } ) -- cgit v1.2.3