From 91f36c3eebf14a07af7fdc13ec53ab2cf4092d87 Mon Sep 17 00:00:00 2001 From: daveoconnor Date: Tue, 10 Dec 2024 09:29:50 -0800 Subject: [PATCH] Simplified/centralised version dropdowns population (#1500) (#1510) --- .pre-commit-config.yaml | 8 +- ak/tests/test_default_pages.py | 18 - ak/views.py | 80 +--- config/urls.py | 2 - libraries/forms.py | 6 +- libraries/mixins.py | 43 ++- libraries/tests/test_views.py | 20 +- libraries/utils.py | 7 +- libraries/views.py | 65 +--- templates/homepage_beta.html | 354 ------------------ templates/libraries/detail.html | 141 ++++--- .../libraries/includes/version_alert.html | 4 +- templates/partials/version_select.html | 1 + users/views.py | 18 +- versions/managers.py | 66 ++-- versions/tests/test_managers.py | 4 +- versions/views.py | 1 - 17 files changed, 202 insertions(+), 636 deletions(-) delete mode 100644 templates/homepage_beta.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35b94746..e0c0f116 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ exclude: .*migrations\/.*|static\/img\/.*|static\/animations\/.*|static\/js\/boo repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v5.0.0 hooks: - id: check-case-conflict - id: check-merge-conflict @@ -15,16 +15,16 @@ repos: - id: trailing-whitespace exclude: ^core/tests/content/boost_release[a-zA-Z_]+.html - repo: https://github.com/ambv/black - rev: 23.3.0 + rev: 24.10.0 hooks: - id: black - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.272 + rev: v0.8.2 hooks: - id: ruff args: [--fix] - repo: https://github.com/rtts/djhtml - rev: 3.0.6 + rev: 3.0.7 hooks: - id: djhtml entry: djhtml --tabwidth 2 diff --git a/ak/tests/test_default_pages.py b/ak/tests/test_default_pages.py index e5da7444..86b85b2a 100644 --- a/ak/tests/test_default_pages.py +++ b/ak/tests/test_default_pages.py @@ -18,24 +18,6 @@ def test_homepage(library, version, tp): assert "featured_library" in response.context -def test_homepage_beta(db, tp): - """Ensure we can hit the beta homepage""" - url = tp.reverse("home-beta") - tp.get_check_200(url) - - -def test_homepage_beta_context(db, tp): - """Ensure have the expected context data on the homepage""" - # Use any page that is named 'home' otherwise use / - url = tp.reverse("home-beta") - response = tp.get_check_200(url) - - # Check that "entries" is in the context - assert "entries" in response.context - response = tp.get(url) - tp.response_200(response) - - def test_200_page(db, tp): """Test a 200 OK page""" diff --git a/ak/views.py b/ak/views.py index 93e09a24..91bce07f 100644 --- a/ak/views.py +++ b/ak/views.py @@ -1,4 +1,3 @@ -import requests import structlog from django.conf import settings from django.core.cache import cache @@ -8,10 +7,9 @@ from django.views import View from django.views.generic import TemplateView -from config.settings import JDOODLE_API_CLIENT_ID, JDOODLE_API_CLIENT_SECRET from core.calendar import extract_calendar_events, events_by_month, get_calendar from libraries.constants import LATEST_RELEASE_URL_PATH_STR -from libraries.models import Category, Library +from libraries.models import Library from news.models import Entry from versions.models import Version @@ -80,82 +78,6 @@ def get_featured_library(self, latest_version): return library -class HomepageBetaView(TemplateView): - """ - Boost homepage - """ - - template_name = "homepage_beta.html" - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - libraries, categories = [], [] - if "category" in self.request.GET and self.request.GET["category"] != "": - context["category"] = Category.objects.get( - slug=self.request.GET["category"] - ) - libraries = Library.objects.filter(categories=context["category"]).order_by( - "name" - ) - else: - context["category"] = None - libraries = Library.objects.all().order_by("name") - categories = Category.objects.all().order_by("name") - if "version" in self.request.GET: - context["version"] = Version.objects.filter( - slug=self.request.GET["version"] - ).first() - else: - context["version"] = Version.objects.most_recent() - if "library" in self.request.GET: - context["library"] = Library.objects.filter( - slug=self.request.GET["library"] - ).first() - categories = context["library"].categories.order_by("name") - if "category" in self.request.GET and self.request.GET["category"] != "": - context["category"] = categories.filter( - slug=self.request.GET["category"] - ).first() - libraries = ( - Library.objects.filter(categories__in=categories) - .order_by("name") - .all() - ) - else: - context["library"] = ( - libraries[0] if libraries else Library.objects.order_by("name").first() - ) - if "category" in self.request.GET and self.request.GET["category"] != "": - context["category"] = categories.filter( - slug=self.request.GET["category"] - ).first() - - context["versions"] = Version.objects.active().order_by("-release_date") - context["libraries"] = libraries - context["categories"] = categories - - context["entries"] = Entry.objects.published().order_by("-publish_at")[:2] - return context - - def post(self, request, *args, **kwargs): - code = request.POST.get("code", "") - if not code: - return render(request, self.template_name) - api_url = "https://api.jdoodle.com/v1/execute" - data = { - "clientId": JDOODLE_API_CLIENT_ID, - "clientSecret": JDOODLE_API_CLIENT_SECRET, - "script": code, - "language": "cpp", - "versionIndex": "3", - } - response = requests.post(api_url, json=data) - result = response.json() - output = result.get("output", "") - error = result.get("error", "") - return render(request, self.template_name, {"output": output, "error": error}) - - class ForbiddenView(View): """ This view raises an exception to test our 403.html template diff --git a/config/urls.py b/config/urls.py index fee92c8d..42fead5f 100755 --- a/config/urls.py +++ b/config/urls.py @@ -7,7 +7,6 @@ from ak.views import ( ForbiddenView, - HomepageBetaView, HomepageView, InternalServerErrorView, NotFoundView, @@ -89,7 +88,6 @@ urlpatterns = ( [ path("", HomepageView.as_view(), name="home"), - path("homepage-beta/", HomepageBetaView.as_view(), name="home-beta"), path("admin/", admin.site.urls), path("oauth2/", include("oauth2_provider.urls", namespace="oauth2_provider")), path("feed/downloads.rss", RSSVersionFeed(), name="downloads_feed_rss"), diff --git a/libraries/forms.py b/libraries/forms.py index d7032401..b8dc5e0a 100644 --- a/libraries/forms.py +++ b/libraries/forms.py @@ -233,9 +233,9 @@ class CreateReportForm(CreateReportFullForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields[ - "library_1" - ].help_text = "If none are selected, all libraries will be selected." + self.fields["library_1"].help_text = ( + "If none are selected, all libraries will be selected." + ) @property def cache_key(self): diff --git a/libraries/mixins.py b/libraries/mixins.py index a6067270..d0df5000 100644 --- a/libraries/mixins.py +++ b/libraries/mixins.py @@ -1,7 +1,9 @@ import structlog +from django.shortcuts import get_object_or_404 from django.urls import reverse from libraries.constants import LATEST_RELEASE_URL_PATH_STR +from libraries.models import Library from versions.models import Version logger = structlog.get_logger() @@ -25,24 +27,37 @@ def get_context_data(self, **kwargs): class BoostVersionMixin: - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - # todo: replace get_current_library_version on LibraryDetail with this + - # prefetch_related - context.update( + def dispatch(self, request, *args, **kwargs): + if not self.extra_context: + self.extra_context = {} + + if not self.extra_context.get("current_version"): + self.extra_context["current_version"] = Version.objects.most_recent() + + self.extra_context.update( { "version_str": self.kwargs.get("version_slug"), "LATEST_RELEASE_URL_PATH_STR": LATEST_RELEASE_URL_PATH_STR, } ) - if not context.get("current_version"): - context["current_version"] = Version.objects.most_recent() - - if context["version_str"] == LATEST_RELEASE_URL_PATH_STR: - context["selected_version"] = context["current_version"] - elif context["version_str"]: - context["selected_version"] = Version.objects.get( - slug=context["version_str"] + if self.extra_context["version_str"] == LATEST_RELEASE_URL_PATH_STR: + self.extra_context["selected_version"] = self.extra_context[ + "current_version" + ] + elif self.extra_context["version_str"]: + self.extra_context["selected_version"] = get_object_or_404( + Version, slug=self.extra_context["version_str"] ) - return context + version_path_kwargs = {} + if self.request.resolver_match.view_name == "library-detail": + version_path_kwargs["flag_versions_without_library"] = get_object_or_404( + Library, slug=self.kwargs.get("library_slug") + ) + + self.extra_context["versions"] = Version.objects.get_dropdown_versions( + **version_path_kwargs + ) + # here we hack extra_context into the request so we can access for cookie checks + request.extra_context = self.extra_context + return super().dispatch(request, *args, **kwargs) diff --git a/libraries/tests/test_views.py b/libraries/tests/test_views.py index 4bb15104..0ddfcb7c 100644 --- a/libraries/tests/test_views.py +++ b/libraries/tests/test_views.py @@ -24,10 +24,6 @@ def test_library_list(library_version, tp, url_name="libraries", request_kwargs= ) baker.make("libraries.LibraryVersion", library=lib2, version=v2) - # Create a version with no libraries - v_no_libraries = baker.make( - "versions.Version", name="boost-1.0.0", release_date=last_year, beta=False - ) url = tp.reverse(url_name, **request_kwargs) res = tp.get(url, **request_kwargs) @@ -38,7 +34,6 @@ def test_library_list(library_version, tp, url_name="libraries", request_kwargs= assert "object_list" in res.context assert library_version in res.context["object_list"] assert lib2 not in res.context["object_list"] - assert v_no_libraries not in res.context["versions"] def test_library_root_redirect_to_grid(tp): @@ -167,17 +162,22 @@ def test_library_detail(library_version, tp): tp.response_200(response) -def test_library_detail_404(library, tp): - """GET /libraries/latest/{bad_library_slug}/""" +def test_library_detail_404(library, old_version, tp): + """GET /library/latest/{bad_library_slug}/""" # 404 due to bad slug url = tp.reverse("library-detail", "latest", "bananas") response = tp.get(url) tp.response_404(response) - # 404 due to no existing version - url = tp.reverse("library-detail", "latest", library.slug) + +def test_library_detail_missing_version(library, old_version, tp): + # custom error due to no existing version + url = tp.reverse("library-detail", old_version.display_name, library.slug) response = tp.get(url) - tp.response_404(response) + assert ( + "There was no version of the Boost.MultiArray library in the 1.70.0 version of " + "Boost." in response.content.decode("utf-8") + ) def test_library_docs_redirect(tp, library, library_version): diff --git a/libraries/utils.py b/libraries/utils.py index e2b1afac..56b57e16 100644 --- a/libraries/utils.py +++ b/libraries/utils.py @@ -143,7 +143,10 @@ def get_category(request): def determine_selected_boost_version(request_value, request): - valid_versions = Version.objects.version_dropdown_strict() + # use the versions in the request if they are available otherwise fall back to DB + valid_versions = getattr(request, "extra_context", {}).get( + "versions", Version.objects.get_dropdown_versions() + ) version_slug = request_value or get_version_from_cookie(request) if version_slug in [v.slug for v in valid_versions] + [LATEST_RELEASE_URL_PATH_STR]: return version_slug @@ -154,7 +157,7 @@ def determine_selected_boost_version(request_value, request): def set_selected_boost_version(version_slug: str, response) -> None: """Update the selected version in the cookies.""" - valid_versions = Version.objects.version_dropdown_strict() + valid_versions = Version.objects.get_dropdown_versions() if version_slug in [v.slug for v in valid_versions]: response.set_cookie(SELECTED_BOOST_VERSION_COOKIE_NAME, version_slug) elif version_slug == LATEST_RELEASE_URL_PATH_STR: diff --git a/libraries/views.py b/libraries/views.py index c7b7bb77..dacbd806 100644 --- a/libraries/views.py +++ b/libraries/views.py @@ -98,9 +98,6 @@ def get_queryset(self): def get_context_data(self, **kwargs): context = super().get_context_data(**self.kwargs) context["categories"] = self.get_categories(context["selected_version"]) - context["versions"] = self.get_versions( - current_version=context["current_version"] - ) # todo: add tests for sort order if self.kwargs.get("category_slug"): context["category"] = Category.objects.get( @@ -116,27 +113,6 @@ def get_categories(self, version=None): .order_by("name") ) - def get_versions(self, current_version): - """ - Return a queryset of all versions to display in the version dropdown. - """ - versions = Version.objects.version_dropdown_strict() - - # Annotate each version with the number of libraries it has - versions = versions.annotate( - library_count=Count("library_version", distinct=True) - ) - - # Filter out versions with no libraries - versions = versions.filter(library_count__gt=0) - - # Confirm the most recent v is in the queryset, even if it has no libraries - if current_version and current_version not in versions: - versions = versions | Version.objects.filter(pk=current_version.pk) - - versions.prefetch_related("library_version") - return versions - def dispatch(self, request, *args, **kwargs): """Set the selected version in the cookies.""" response = super().dispatch(request, *args, **kwargs) @@ -238,21 +214,23 @@ class LibraryDetail(VersionAlertMixin, BoostVersionMixin, DetailView): model = Library template_name = "libraries/detail.html" redirect_to_docs = False + slug_url_kwarg = "library_slug" def get_context_data(self, **kwargs): """Set the form action to the main libraries page""" context = super().get_context_data(**kwargs) - # Get fields related to Boost versions - context["versions"] = ( - Version.objects.version_dropdown_strict() - .filter(library_version__library=self.object) - .distinct() - ) + context["library_view_str"] = get_prioritized_library_view(self.request) + # Get versions, flag when the current library isn't in each version context["LATEST_RELEASE_URL_PATH_NAME"] = LATEST_RELEASE_URL_PATH_STR - # Get general data and version-sensitive data - library_version = LibraryVersion.objects.get( - library=self.get_object(), version=context["selected_version"] - ) + if not self.object: + raise Http404("No library found matching the query") + try: + library_version = LibraryVersion.objects.get( + library=self.object, version=context["selected_version"] + ) + except LibraryVersion.DoesNotExist: + return context + context["library_version"] = library_version context["documentation_url"] = get_documentation_url( library_version, context["version_str"] == LATEST_RELEASE_URL_PATH_STR @@ -305,7 +283,6 @@ def get_context_data(self, **kwargs): self.object.get_description(client, tag=context["selected_version"].name) or README_MISSING ) - context["library_view_str"] = get_prioritized_library_view(self.request) return context def get_commit_data_by_release(self): @@ -325,24 +302,6 @@ def get_commit_data_by_release(self): for x in reversed(list(qs)) ] - def get_object(self): - """Get the current library object from the slug in the URL. - If present, use the version_slug to get the right LibraryVersion of the library. - Otherwise, default to the most recent version.""" - library_slug = self.kwargs.get("library_slug") - version = self.get_version() - - if not LibraryVersion.objects.filter( - version=version, library__slug__iexact=library_slug - ).exists(): - raise Http404("No library found matching the query") - - try: - obj = self.get_queryset().get(slug__iexact=library_slug) - except self.model.DoesNotExist: - raise Http404("No library found matching the query") - return obj - def get_author_tag(self): """Format the authors for the author meta tag in the template.""" authors = self.object.authors.all() diff --git a/templates/homepage_beta.html b/templates/homepage_beta.html deleted file mode 100644 index 5bb0ba17..00000000 --- a/templates/homepage_beta.html +++ /dev/null @@ -1,354 +0,0 @@ -{% extends "base.html" %} -{% load static %} -{% debug %} -{% block content %} -
- {% comment %} Homepage Hero {% endcomment %} -
-
-
-

Boost your C++

-

- Home to 165+ free, peer-reviewed, portable libraries to increase your - productivity across all industry domains. -

- - - Download Latest - - - Version Details - -
-
-
- {% comment %} Section 2 {% endcomment %} -
-
-
-
- library spotlight -
- -

Accumulators

- - Framework for incremental calculation, and collection of statistical accumulators. - -
-
- - -
-
- - -
-
- - -
-
-
-
- -
-
-
- {% comment %} Section 3 - Events {% endcomment %} -
-
-
-
- schedule of events -
-
-
-
- -
-
-

May 2023

- - 29th: SAM review -
-
-
-
-
-
-

June 2023

- - 29th: SAM review -
-
-
-
-
-
-

July 2023

- - 29th: SAM review -
-
-
-
- -
-
- -
-
- -
-
-
-
-
-
- {% comment %} Section 4 - News {% endcomment %} -
-
-
-
- news from boost and c++ -
-
-
- {% if entries %} - {% for entry in entries %} -
-
-

{{ entry.title }}

-

{{ entry.publish_at|date:"m/d/Y" }}

-

- {{ entry.content|truncatewords:20 }}... Read More -

- {% if entry.image %} - - {% endif %} -
-
- {% endfor %} - {% endif %} -
-
-
- {% comment %} Section 5 - Activity {% endcomment %} -
-
-
-
- activity April 21, 2023 - May 20, 2023 -
-
- -
-
- - - - - -
-
-
-
6,801
-

Commits

-
-
-
1,023
-

CI Runs

-
-
-
-
Pull Requests
-
-
210
-

Open

-
-
-
15
-

New

-
-
-
50
-

Active

-
-
-
-
Issues
-
-
210
-

Open

-
-
-
15
-

New

-
-
-
50
-

Active

-
-
-
-
-
- - - - - -
-
-
-
500,000
-

JFrog

-
-
-
177,000
-

Conan

-
-
-
226,000
-

vcpkg

-
-
-
-
-
- - - - - -
-
-
-
500,000
-

Mailing List Messages

-
-
-
177,000
-

Slack Posts -

-
-
-
-
-
-
-
- - {% comment %} Section 6 - New to Boost {% endcomment %} -
-
-
-
- new to boost? -
-
-
-
-
- {% comment %} Section 7 - Contribute {% endcomment %} -
-
-
-
- contribute -
-
-
-
-
-
-{% endblock content %} -{% block footer_js %} -{% endblock footer_js %} diff --git a/templates/libraries/detail.html b/templates/libraries/detail.html index 74641d56..ea9b23f4 100644 --- a/templates/libraries/detail.html +++ b/templates/libraries/detail.html @@ -1,8 +1,14 @@ {% extends "base.html" %} {% load i18n static avatar_tags version_select %} -{% block title %}{{ object.display_name }} ({{ version.display_name }}){% endblock %} -{% block description %}{% if library_version.description %}{% trans library_version.description %}{% endif %}{% endblock %} +{% block title %}{% if object %}{{ object.display_name }} {% else %} {{ object.name }} {% endif %}({{ selected_version.display_name }}){% endblock %} +{% block description %} + {% if library_version.description %} + {% trans library_version.description %} + {% elif object.description %} + {{ object.description }} + {% endif %} +{% endblock %} {% block author %}{{ author_tag }}{% endblock %} {% block content %} @@ -13,7 +19,6 @@
{{ object.display_name }} -
@@ -23,74 +28,88 @@ {% include "libraries/includes/version_alert.html" %} -
+ {% if library_version %} +
+
-
-
- -
- - C++ - {% if library_version.cpp_standard_minimum %}{{ library_version.cpp_standard_minimum }}{% else %}03{% endif %} - - {% if object.first_boost_version %}Added in Boost - {{ object.first_boost_version.display_name }}{% endif %} -
- -
-
- Categories: - {% for category in object.categories.all %} - {{ category.name }} - {% if not forloop.last %}, {% endif %} - {% endfor %} +
+ + C++ + {% if library_version.cpp_standard_minimum %}{{ library_version.cpp_standard_minimum }}{% else %}03{% endif %} + + {% if object.first_boost_version %}Added in Boost + {{ object.first_boost_version.display_name }}{% endif %}
-

{{ library_version.description|default:"No description provide for this version." }}

-
+
+
+ Categories: + {% for category in object.categories.all %} + {{ category.name }} + {% if not forloop.last %}, {% endif %} + {% endfor %} +
- - -
- - - Source Code - {{ github_url|cut:"https://" }} - +

{{ library_version.description|default:"No description provide for this version." }}

+
+ + + +
-
-
-
-
-
-
{# Commits per Release #}
+
+
+
+
+
{# Commits per Release #}
+
-
+ {% else %} + {% if object.first_boost_version %} +
+ There was no version of the {{object.display_name}} library in the + {{selected_version.display_name}} version of Boost. The + first release of the {{ object.display_name }} library in Boost + was {{ object.first_boost_version.display_name }}. +
+ {% else %} +
+ There was no version of the {{object.display_name}} library in the {{selected_version.display_name}} version of Boost. +
+ {% endif %} + + {% endif %}
diff --git a/templates/libraries/includes/version_alert.html b/templates/libraries/includes/version_alert.html index b3368566..6956b0d2 100644 --- a/templates/libraries/includes/version_alert.html +++ b/templates/libraries/includes/version_alert.html @@ -7,8 +7,8 @@ {% else %} {% if selected_version.beta %} This is a beta version of Boost. - {% elif version.full_release %} - This is an older version and was released in {{ selected_version.release_date|date:"Y"}}. + {% elif selected_version.full_release %} + This is an older version of Boost and was released in {{ selected_version.release_date|date:"Y"}}. {% else %} This version of Boost is under active development. {% endif %} diff --git a/templates/partials/version_select.html b/templates/partials/version_select.html index ac75f293..baf5c5e5 100644 --- a/templates/partials/version_select.html +++ b/templates/partials/version_select.html @@ -12,6 +12,7 @@ {% for v in versions %} diff --git a/users/views.py b/users/views.py index e804f133..f73881f7 100644 --- a/users/views.py +++ b/users/views.py @@ -225,9 +225,9 @@ def check_and_send_reset_email(self, form, message=None): form = ResetPasswordForm({"email": email}) if form.is_valid(): form.save(request=self.request) - self.request.session[ - "contributor_account_redirect_message" - ] = message + self.request.session["contributor_account_redirect_message"] = ( + message + ) return HttpResponseRedirect(reverse_lazy("account_login")) return None @@ -286,9 +286,9 @@ def get_context_data(self, **kwargs): class CustomEmailVerificationSentView(EmailVerificationSentView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context[ - "EMAIL_CONFIRMATION_EXPIRE_DAYS" - ] = app_settings.EMAIL_CONFIRMATION_EXPIRE_DAYS + context["EMAIL_CONFIRMATION_EXPIRE_DAYS"] = ( + app_settings.EMAIL_CONFIRMATION_EXPIRE_DAYS + ) return context @@ -325,9 +325,9 @@ def form_valid(self, form): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context[ - "ACCOUNT_DELETION_GRACE_PERIOD_DAYS" - ] = settings.ACCOUNT_DELETION_GRACE_PERIOD_DAYS + context["ACCOUNT_DELETION_GRACE_PERIOD_DAYS"] = ( + settings.ACCOUNT_DELETION_GRACE_PERIOD_DAYS + ) return context diff --git a/versions/managers.py b/versions/managers.py index c793f16c..191e5ef1 100644 --- a/versions/managers.py +++ b/versions/managers.py @@ -1,5 +1,5 @@ from django.db import models -from django.db.models import Func, Value +from django.db.models import Func, Value, Count from django.db.models.functions import Replace from django.contrib.postgres.fields import ArrayField @@ -78,14 +78,32 @@ def minor_versions(self): """ return self.get_queryset().with_version_split().filter(patch=0) - def version_dropdown(self, exclude_branches=True): - """Return the versions that should show in the version drop-down""" + def get_dropdown_versions( + self, + *, + flag_versions_without_library: "Library" = None, # noqa: F821 + order_by: str = "-name", + ): + """ + Returns the versions to be shown in the drop-down, basics: + * does not include the development branches + * includes the most recent beta if it is newer than the most recent full release + * doesn't return versions where full_release=False and beta=False + + Args: + order_by (str): the field to order by + flag_versions_without_library (Library): flag the version when it doesn't + have the matching library - e.g. used for library detail page + """ all_versions = self.active().filter(beta=False) - most_recent = self.most_recent() most_recent_beta = self.most_recent_beta() - def should_show_beta(most_recent, most_recent_beta): - """Returns bool for whether to show beta version in dropdown""" + def should_show_beta(most_recent_beta): + """ + Returns bool for whether to show beta version in dropdown. Returns True only + when the most recent beta version is newer than the most recent full release + """ + most_recent = self.most_recent() if not most_recent_beta or most_recent is None: return False @@ -94,27 +112,31 @@ def should_show_beta(most_recent, most_recent_beta): > most_recent.cleaned_version_parts ) - include_beta = should_show_beta(most_recent, most_recent_beta) - + queryset = all_versions + include_beta = should_show_beta(most_recent_beta) if include_beta: beta_queryset = self.active().filter(models.Q(name=most_recent_beta.name)) - queryset = all_versions | beta_queryset - else: - queryset = all_versions + queryset = queryset | beta_queryset - if exclude_branches: - queryset = queryset.exclude(name__in=["develop", "master", "head"]) - - return queryset.order_by("-name").defer("data") + queryset = ( + queryset.exclude(name__in=["develop", "master", "head"]) + .exclude(full_release=False, beta=False) + .defer("data") + ) - def version_dropdown_strict(self, *, exclude_branches=True): - """Returns the versions to be shown in the drop-down, but does not include - the development branches""" - versions = self.version_dropdown(exclude_branches=exclude_branches) - # exclude if full_release is False and beta is False - versions = versions.exclude(full_release=False, beta=False) + if flag_versions_without_library: + # Annotate each version with a flag `has_library` indicating if it has the + # provided library version or not + queryset = queryset.annotate( + has_library=Count( + "library_version", + filter=models.Q( + library_version__library=flag_versions_without_library + ), + ) + ) - return versions + return queryset.order_by(order_by) class VersionFileQuerySet(models.QuerySet): diff --git a/versions/tests/test_managers.py b/versions/tests/test_managers.py index 31ab1283..3ef29c05 100644 --- a/versions/tests/test_managers.py +++ b/versions/tests/test_managers.py @@ -62,7 +62,7 @@ def test_version_dropdown( else: most_recent_beta = None - queryset = Version.objects.version_dropdown() + queryset = Version.objects.get_dropdown_versions() if should_show_beta: beta_queryset = Version.objects.active().filter(Q(name=most_recent_beta.name)) @@ -126,7 +126,7 @@ def test_version_dropdown_strict( beta_version.full_release = False beta_version.save() - queryset = Version.objects.version_dropdown_strict() + queryset = Version.objects.get_dropdown_versions() assert (version in queryset) == should_be_included diff --git a/versions/views.py b/versions/views.py index ec123c37..90d6532d 100755 --- a/versions/views.py +++ b/versions/views.py @@ -47,7 +47,6 @@ def get_context_data(self, **kwargs): context["is_current_release"] = False return context - context["versions"] = Version.objects.version_dropdown_strict() downloads = obj.downloads.all().order_by("operating_system") context["downloads"] = { k: list(v)