mirror of
https://github.com/boostorg/website-v2.git
synced 2026-01-19 04:42:17 +00:00
There's a good amount of refactoring in this, so this is going to look like a much bigger change than it is. In reality it makes the dispatch code simpler. Fixes: 1. Resolved the issue with the libraries pages not redirecting correctly 2. Resolved an issue around categories not being preserved moving from page to page. The issue with the redirects was there was a tug of war on arriving on /library between the various ways of determining where the user should end up. I added a `/libraries/grid/` url and now `/libraries/` determines which list page the user should end up on based on 1) url 2) cookie, 3) the default, same for version preference. We can probably get rid of dispatch() later. This has the added bonus of allowing reliable linking to a specific list view (e.g. for users to bookmark one type) Refactors: 1. Separated the navigation on the three library pages into a standalone template. 2. Moved some constants to constants.py 3. Moved a lot of the views methods which were only used by the dispatch() call to utils.py . 4. At that stage there were circular imports so I moved the docs generation functions which were only used in constants.py to constants_utils.py. utils.py is more general.
This commit is contained in:
@@ -149,8 +149,9 @@ urlpatterns = (
|
||||
LibraryListByCategory.as_view(),
|
||||
name="libraries-by-category",
|
||||
),
|
||||
path("libraries/mini/", LibraryListMini.as_view(), name="libraries-mini"),
|
||||
path("libraries/", LibraryList.as_view(), name="libraries"),
|
||||
path("libraries/mini/", LibraryListMini.as_view(), name="libraries-mini"),
|
||||
path("libraries/grid/", LibraryList.as_view(), name="libraries-grid"),
|
||||
path(
|
||||
"libraries/<slug:slug>/<slug:version_slug>/",
|
||||
LibraryDetail.as_view(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .utils import (
|
||||
from .constants_utils import (
|
||||
generate_library_docs_url,
|
||||
generate_library_docs_url_v2,
|
||||
generate_library_docs_url_v3,
|
||||
@@ -11,18 +11,17 @@ from .utils import (
|
||||
generate_library_docs_url_utility_v3,
|
||||
generate_library_docs_url_circular_buffer,
|
||||
generate_library_docs_url_core,
|
||||
generate_library_docs_url_double_nested_library_htm,
|
||||
generate_library_docs_url_double_nested_library_html,
|
||||
generate_library_docs_url_double_nested_library_htm,
|
||||
generate_library_docs_url_algorithm,
|
||||
generate_library_docs_url_numeric,
|
||||
generate_library_docs_url_numeric_2,
|
||||
generate_library_docs_url_string_ref,
|
||||
generate_library_docs_url_string_view,
|
||||
generate_library_docs_url_utility_anchor,
|
||||
generate_library_docs_url_throwexception,
|
||||
generate_library_docs_url_utility_anchor,
|
||||
)
|
||||
|
||||
|
||||
# Mapping for exeptions to loading URLs for older docs.
|
||||
# key: Taken from Library.slug
|
||||
# value: List of dictionaries with instructions for how to format docs URLs for
|
||||
@@ -309,3 +308,7 @@ SKIP_LIBRARY_VERSIONS = {
|
||||
|
||||
# List of versions for which we know docs are missing
|
||||
VERSION_DOCS_MISSING = ["boost-1.33.0"]
|
||||
|
||||
DEFAULT_LIBRARIES_LANDING_VIEW = "libraries-grid"
|
||||
SELECTED_BOOST_VERSION_COOKIE_NAME = "boost_version"
|
||||
SELECTED_LIBRARY_VIEW_COOKIE_NAME = "library_view"
|
||||
|
||||
157
libraries/constants_utils.py
Normal file
157
libraries/constants_utils.py
Normal file
@@ -0,0 +1,157 @@
|
||||
def generate_library_docs_url(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
General use
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_v2(boost_url_slug, library_slug):
|
||||
""" "Generate a documentation url with a specific format
|
||||
|
||||
For use primarily with IO, versions 1.73.0 and up
|
||||
"""
|
||||
new_boost_url_slug = boost_url_slug.replace("boost_", "")
|
||||
return f"/doc/libs/{new_boost_url_slug}/libs/{library_slug}/doc/html/{library_slug}.html" # noqa
|
||||
|
||||
|
||||
def generate_library_docs_url_v3(boost_url_slug, library_slug):
|
||||
""" "Generate a documentation url with a specific format
|
||||
|
||||
For use primarily with IO, versions 1.64.0-1.72.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_v4(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Any, versions 1.33.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_bind_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Member Function, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/bind/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_bind_v2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Member Function, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/bind/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_math_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Math Common Factor, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/math/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Call Traits, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}.htm"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Identity Types, version 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v3(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
Same as v1, but .html and not .htm
|
||||
|
||||
First used for In Place Factories, version 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_circular_buffer(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Circular Buffer v. 1.54.0 and before"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_core(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Enable If, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/core/doc/html/core/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_double_nested_library_html(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Dynamic Bitset, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_double_nested_library_htm(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
Ends in .htm, not .html
|
||||
|
||||
First used for Dynamic Bitset, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/{library_slug}.htm"
|
||||
|
||||
|
||||
def generate_library_docs_url_algorithm(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Min Max, versions 1.60.0 and below"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/algorithm/{library_slug}/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_numeric(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Interval, versions 1.60.0 and below"""
|
||||
return (
|
||||
f"/doc/libs/{boost_url_slug}/libs/numeric/{library_slug}/doc/{library_slug}.htm"
|
||||
)
|
||||
|
||||
|
||||
def generate_library_docs_url_numeric_2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Interval, versions 1.60.0 and below"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/numeric/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_string_ref(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-ref library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_string_view(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-view library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/doc/html/utility/utilities/{library_slug}.html" # noqa
|
||||
|
||||
|
||||
def generate_library_docs_url_throwexception(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-view library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/exception/doc/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_anchor(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for a URL that uses an anchor"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/utility.htm#{library_slug}"
|
||||
@@ -6,6 +6,12 @@ from dateutil.relativedelta import relativedelta
|
||||
from libraries.utils import (
|
||||
decode_content,
|
||||
generate_fake_email,
|
||||
get_first_last_day_last_month,
|
||||
parse_date,
|
||||
version_within_range,
|
||||
write_content_to_tempfile,
|
||||
)
|
||||
from libraries.constants_utils import (
|
||||
generate_library_docs_url,
|
||||
generate_library_docs_url_v2,
|
||||
generate_library_docs_url_v3,
|
||||
@@ -18,15 +24,11 @@ from libraries.utils import (
|
||||
generate_library_docs_url_utility_v3,
|
||||
generate_library_docs_url_circular_buffer,
|
||||
generate_library_docs_url_core,
|
||||
generate_library_docs_url_double_nested_library_htm,
|
||||
generate_library_docs_url_double_nested_library_html,
|
||||
generate_library_docs_url_double_nested_library_htm,
|
||||
generate_library_docs_url_numeric,
|
||||
generate_library_docs_url_string_ref,
|
||||
generate_library_docs_url_string_view,
|
||||
get_first_last_day_last_month,
|
||||
parse_date,
|
||||
version_within_range,
|
||||
write_content_to_tempfile,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ def test_library_list(library_version, tp, url_name="libraries"):
|
||||
)
|
||||
|
||||
res = tp.get(url_name)
|
||||
if url_name == "libraries":
|
||||
tp.response_302(res)
|
||||
return
|
||||
tp.response_200(res)
|
||||
assert "library_list" in res.context
|
||||
assert library_version.library in res.context["library_list"]
|
||||
@@ -36,11 +39,18 @@ def test_library_list(library_version, tp, url_name="libraries"):
|
||||
assert v_no_libraries not in res.context["versions"]
|
||||
|
||||
|
||||
def test_library_root_redirect_to_grid(tp):
|
||||
"""GET /"""
|
||||
res = tp.get("libraries")
|
||||
tp.response_302(res)
|
||||
assert res.url == "/libraries/grid/"
|
||||
|
||||
|
||||
def test_library_list_no_data(tp):
|
||||
"""GET /libraries/"""
|
||||
Library.objects.all().delete()
|
||||
Version.objects.all().delete()
|
||||
res = tp.get("libraries")
|
||||
res = tp.get("libraries-grid")
|
||||
tp.response_200(res)
|
||||
|
||||
|
||||
@@ -67,7 +77,7 @@ def test_library_list_no_pagination(library_version, tp):
|
||||
).library
|
||||
for i in range(30)
|
||||
] + [library_version.library]
|
||||
res = tp.get("libraries")
|
||||
res = tp.get("libraries-grid")
|
||||
tp.response_200(res)
|
||||
|
||||
library_list = res.context.get("library_list")
|
||||
@@ -86,7 +96,7 @@ def test_library_list_select_category(library_version, category, tp):
|
||||
new_lib_version = baker.make(
|
||||
"libraries.LibraryVersion", version=library_version.version, library=new_lib
|
||||
)
|
||||
res = tp.get(f"/libraries/?category={category.slug}")
|
||||
res = tp.get(f"/libraries/grid/?category={category.slug}")
|
||||
tp.response_200(res)
|
||||
assert library_version.library in res.context["library_list"]
|
||||
assert new_lib_version.library not in res.context["library_list"]
|
||||
|
||||
@@ -11,6 +11,12 @@ from django.utils.text import slugify
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect
|
||||
|
||||
from libraries.constants import (
|
||||
DEFAULT_LIBRARIES_LANDING_VIEW,
|
||||
SELECTED_BOOST_VERSION_COOKIE_NAME,
|
||||
SELECTED_LIBRARY_VIEW_COOKIE_NAME,
|
||||
)
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
@@ -32,165 +38,6 @@ def generate_fake_email(val: str) -> str:
|
||||
return f"{local_email}@example.com"
|
||||
|
||||
|
||||
def generate_library_docs_url(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
General use
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_v2(boost_url_slug, library_slug):
|
||||
""" "Generate a documentation url with a specific format
|
||||
|
||||
For use primarily with IO, versions 1.73.0 and up
|
||||
"""
|
||||
new_boost_url_slug = boost_url_slug.replace("boost_", "")
|
||||
return f"/doc/libs/{new_boost_url_slug}/libs/{library_slug}/doc/html/{library_slug}.html" # noqa
|
||||
|
||||
|
||||
def generate_library_docs_url_v3(boost_url_slug, library_slug):
|
||||
""" "Generate a documentation url with a specific format
|
||||
|
||||
For use primarily with IO, versions 1.64.0-1.72.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_v4(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Any, versions 1.33.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_bind_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Member Function, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/bind/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_bind_v2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Member Function, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/bind/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_math_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Math Common Factor, versions 1.60.0 and older
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/math/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v1(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Call Traits, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}.htm"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Identity Types, version 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_v3(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
Same as v1, but .html and not .htm
|
||||
|
||||
First used for In Place Factories, version 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_circular_buffer(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Circular Buffer v. 1.54.0 and before"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/doc/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_core(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Enable If, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/core/doc/html/core/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_double_nested_library_html(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used for Dynamic Bitset, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_double_nested_library_htm(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
Ends in .htm, not .html
|
||||
|
||||
First used for Dynamic Bitset, versions 1.60.0 and below.
|
||||
"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/{library_slug}/{library_slug}.htm"
|
||||
|
||||
|
||||
def generate_library_docs_url_algorithm(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Min Max, versions 1.60.0 and below"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/algorithm/{library_slug}/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_numeric(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Interval, versions 1.60.0 and below"""
|
||||
return (
|
||||
f"/doc/libs/{boost_url_slug}/libs/numeric/{library_slug}/doc/{library_slug}.htm"
|
||||
)
|
||||
|
||||
|
||||
def generate_library_docs_url_numeric_2(boost_url_slug, library_slug):
|
||||
"""Generate a documentation url with a specific format
|
||||
|
||||
First used with Interval, versions 1.60.0 and below"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/numeric/{library_slug}/doc/html/index.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_string_ref(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-ref library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/doc/html/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_string_view(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-view library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/doc/html/utility/utilities/{library_slug}.html" # noqa
|
||||
|
||||
|
||||
def generate_library_docs_url_throwexception(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for the string-view library-versions"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/exception/doc/{library_slug}.html"
|
||||
|
||||
|
||||
def generate_library_docs_url_utility_anchor(boost_url_slug, library_slug):
|
||||
"""Generate a documentation URL for a URL that uses an anchor"""
|
||||
return f"/doc/libs/{boost_url_slug}/libs/utility/utility.htm#{library_slug}"
|
||||
|
||||
|
||||
def generate_random_string(length=4):
|
||||
characters = string.ascii_letters
|
||||
random_string = "".join(random.choice(characters) for _ in range(length))
|
||||
@@ -244,5 +91,76 @@ def redirect_to_view_with_params(view_name, params, query_params):
|
||||
"""Redirect to a view with parameters and query parameters."""
|
||||
base_url = reverse(view_name, kwargs=params)
|
||||
query_string = urlencode(query_params)
|
||||
url = "{}?{}".format(base_url, query_string)
|
||||
url = base_url
|
||||
if query_string:
|
||||
url = "{}?{}".format(base_url, query_string)
|
||||
return redirect(url)
|
||||
|
||||
|
||||
def get_version_from_url(request):
|
||||
return request.GET.get("version")
|
||||
|
||||
|
||||
def get_version_from_cookie(request):
|
||||
return request.COOKIES.get(SELECTED_BOOST_VERSION_COOKIE_NAME)
|
||||
|
||||
|
||||
def get_view_from_url(request):
|
||||
return request.GET.get("view")
|
||||
|
||||
|
||||
def get_view_from_cookie(request):
|
||||
return request.COOKIES.get(SELECTED_LIBRARY_VIEW_COOKIE_NAME)
|
||||
|
||||
|
||||
def set_view_in_cookie(response, view):
|
||||
response.set_cookie(SELECTED_LIBRARY_VIEW_COOKIE_NAME, view)
|
||||
|
||||
|
||||
def get_prioritized_version(request):
|
||||
"""
|
||||
Version Priorities:
|
||||
1. URL parameter
|
||||
2. Cookie
|
||||
3. Default to latest version
|
||||
"""
|
||||
url_version = get_version_from_url(request)
|
||||
cookie_version = get_version_from_cookie(request)
|
||||
default_version = None
|
||||
return url_version or cookie_version or default_version
|
||||
|
||||
|
||||
def get_prioritized_library_view(request):
|
||||
"""
|
||||
View Priorities:
|
||||
1. URL parameter
|
||||
2. Cookie
|
||||
3. Default to grid view
|
||||
"""
|
||||
url_view = get_view_from_url(request)
|
||||
cookie_view = get_view_from_cookie(request)
|
||||
return url_view or cookie_view or DEFAULT_LIBRARIES_LANDING_VIEW
|
||||
|
||||
|
||||
def build_view_query_params_from_request(request):
|
||||
query_params = {}
|
||||
version = get_prioritized_version(request)
|
||||
category = get_category(request)
|
||||
if version and version != "latest":
|
||||
query_params["version"] = version
|
||||
if category:
|
||||
query_params["category"] = category
|
||||
return query_params
|
||||
|
||||
|
||||
def get_category(request):
|
||||
return request.GET.get("category", "")
|
||||
|
||||
|
||||
def build_route_name_for_view(view):
|
||||
return f"libraries-{view}"
|
||||
|
||||
|
||||
def determine_view_from_library_request(request):
|
||||
split_path_info = request.path_info.split("/")
|
||||
return None if split_path_info[-2] == "libraries" else split_path_info[-2]
|
||||
|
||||
@@ -17,10 +17,16 @@ from versions.models import Version
|
||||
from .forms import VersionSelectionForm
|
||||
from .mixins import VersionAlertMixin
|
||||
from .models import Category, CommitData, Library, LibraryVersion
|
||||
from .utils import redirect_to_view_with_params
|
||||
|
||||
SELECTED_BOOST_VERSION_COOKIE_NAME = "boost_version"
|
||||
SELECTED_LIBRARY_VIEW_COOKIE_NAME = "library_view"
|
||||
from .utils import (
|
||||
redirect_to_view_with_params,
|
||||
get_view_from_cookie,
|
||||
set_view_in_cookie,
|
||||
get_prioritized_library_view,
|
||||
build_view_query_params_from_request,
|
||||
build_route_name_for_view,
|
||||
determine_view_from_library_request,
|
||||
)
|
||||
from .constants import SELECTED_BOOST_VERSION_COOKIE_NAME
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
@@ -46,7 +52,6 @@ class LibraryList(VersionAlertMixin, ListView):
|
||||
version_slug = self.request.COOKIES.get(
|
||||
SELECTED_BOOST_VERSION_COOKIE_NAME, None
|
||||
)
|
||||
|
||||
if version_slug is None:
|
||||
version_slug = self.request.GET.get("version", None)
|
||||
|
||||
@@ -59,26 +64,13 @@ class LibraryList(VersionAlertMixin, ListView):
|
||||
def set_selected_boost_version(self, response, version: str) -> None:
|
||||
"""Set the selected version in the cookies."""
|
||||
valid_versions = Version.objects.version_dropdown_strict()
|
||||
|
||||
if version in [v.slug for v in valid_versions] or version == "latest":
|
||||
if version in [v.slug for v in valid_versions]:
|
||||
response.set_cookie(SELECTED_BOOST_VERSION_COOKIE_NAME, version)
|
||||
elif version == "latest":
|
||||
response.delete_cookie(SELECTED_BOOST_VERSION_COOKIE_NAME)
|
||||
else:
|
||||
logger.warning(f"Attempted to set invalid version slug: {version}")
|
||||
|
||||
def get_selected_library_view(self) -> str:
|
||||
"""Get the user's preferred view for the libraries page."""
|
||||
return self.request.COOKIES.get(SELECTED_LIBRARY_VIEW_COOKIE_NAME)
|
||||
|
||||
def set_selected_library_view(
|
||||
self, response, view: str, *, clear: bool = False
|
||||
) -> str:
|
||||
"""Set the user's preferred view for the libraries page."""
|
||||
if clear:
|
||||
response.delete_cookie(SELECTED_LIBRARY_VIEW_COOKIE_NAME)
|
||||
else:
|
||||
response.set_cookie(SELECTED_LIBRARY_VIEW_COOKIE_NAME, view)
|
||||
return view
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
params = self.request.GET.copy()
|
||||
@@ -141,6 +133,7 @@ class LibraryList(VersionAlertMixin, ListView):
|
||||
context["categories"] = self.get_categories(context["version"])
|
||||
context["versions"] = self.get_versions()
|
||||
context["library_list"] = self.get_queryset()
|
||||
context["url_params"] = build_view_query_params_from_request(self.request)
|
||||
return context
|
||||
|
||||
def get_categories(self, version=None):
|
||||
@@ -174,72 +167,24 @@ class LibraryList(VersionAlertMixin, ListView):
|
||||
versions = versions.exclude(name__in=["develop", "master", "head"])
|
||||
return versions
|
||||
|
||||
def get_version_request_from_url(self):
|
||||
return self.request.GET.get("version")
|
||||
|
||||
def view_route_from_url(self):
|
||||
path_info = self.request.path_info
|
||||
|
||||
# Determine the route name based on the URL.
|
||||
if "/by-category/" in path_info:
|
||||
route_name = "libraries-by-category"
|
||||
elif "/mini/" in path_info:
|
||||
route_name = "libraries-mini"
|
||||
else:
|
||||
route_name = "libraries"
|
||||
|
||||
return route_name
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
"""Set the selected version in the cookies."""
|
||||
response = super().dispatch(request, *args, **kwargs)
|
||||
query_params = build_view_query_params_from_request(request)
|
||||
# check if one was set, if not then default to cookie value for latest
|
||||
# (practically speaking, that means no cookie)
|
||||
self.set_selected_boost_version(response, query_params.get("version", "latest"))
|
||||
|
||||
# If the user has requested a reset, clear the session value.
|
||||
if "reset_view" in request.GET:
|
||||
self.set_selected_library_view(response, "", clear=True)
|
||||
view = determine_view_from_library_request(request)
|
||||
# The following conditional practically only applies on "/libraries/", at
|
||||
# which point the redirection will be determined by prioritised view
|
||||
if not view:
|
||||
view = get_prioritized_library_view(request)
|
||||
set_view_in_cookie(response, build_route_name_for_view(view))
|
||||
return redirect_to_view_with_params(view, kwargs, query_params)
|
||||
|
||||
# Determine the route name based on the URL.
|
||||
route_name = self.view_route_from_url()
|
||||
if route_name in ["libraries-mini", "libraries-by-category"]:
|
||||
self.set_selected_library_view(response, route_name)
|
||||
|
||||
redirect_to_version = self.get_selected_boost_version()
|
||||
redirect_to_route = self.get_selected_library_view()
|
||||
route_in_url = self.view_route_from_url()
|
||||
version_in_url = self.get_version_request_from_url()
|
||||
|
||||
# If the user has a preferred view, use that.
|
||||
if redirect_to_route and route_in_url != redirect_to_route:
|
||||
if "reset_view" not in request.GET:
|
||||
self.set_selected_library_view(response, route_name)
|
||||
return redirect(redirect_to_route)
|
||||
route_name = redirect_to_route
|
||||
|
||||
# Set the cookie value to the version in the URL.
|
||||
if version_in_url:
|
||||
self.set_selected_boost_version(response, version_in_url)
|
||||
else:
|
||||
# If no version is present in the URL, default to the cookie value.
|
||||
if redirect_to_version:
|
||||
# Construct the URL with the version from the cookie.
|
||||
current_category = request.GET.get("category", "")
|
||||
reset_view = "reset_view" in request.GET
|
||||
|
||||
query_params = {
|
||||
"category": current_category,
|
||||
"version": redirect_to_version,
|
||||
}
|
||||
if reset_view:
|
||||
query_params.update(reset_view="1")
|
||||
|
||||
if not current_category:
|
||||
del query_params["category"]
|
||||
|
||||
# Redirect to the correct view with the correct version.
|
||||
redirect_to_route = self.get_selected_library_view()
|
||||
route_name = redirect_to_route if redirect_to_route else route_name
|
||||
|
||||
return redirect_to_view_with_params(route_name, kwargs, query_params)
|
||||
if view != get_view_from_cookie(request):
|
||||
set_view_in_cookie(response, build_route_name_for_view(view))
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -33,62 +33,7 @@
|
||||
{% endcomment %}
|
||||
</div>
|
||||
|
||||
<div class="pt-2 px-0 mb-2 text-right md:mb-2 mx-3 md:mx-0">
|
||||
|
||||
<form action="." method="get">
|
||||
<div class="flex relative space-x-3 justify-start">
|
||||
{# Search #}
|
||||
{% comment %} {% include "libraries/includes/search_input.html" %} {% endcomment %}
|
||||
|
||||
{# Select a category #}
|
||||
{% comment %}
|
||||
<div>
|
||||
{# todo: if someone selects a category and hits back, it retains their choice here. #}
|
||||
<select onchange="this.form.submit()"
|
||||
name="category"
|
||||
class="block py-2 pr-11 pl-5 mb-3 w-full text-sm bg-white rounded-md border border-gray-300 cursor-pointer sm:inline-block md:mb-0 md:w-auto dark:bg-black dark:border-slate"
|
||||
id="id_category"
|
||||
disabled
|
||||
>
|
||||
<option value="">Filter by category</option>
|
||||
{% for c in categories %}
|
||||
<option value="{{ c.slug }}" {% if category == c %}selected="selected"{% endif %}>{{ c.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endcomment %}
|
||||
|
||||
{# Display options #}
|
||||
<div class=" flex space-x-3">
|
||||
<div class="relative group">
|
||||
<a title="Name View" href="{% url 'libraries-mini' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-list p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">List View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Grid View" href="{% url 'libraries' %}?reset_view=1"><i class="link rounded border border-gray-300 cursor-pointer fas fa-th-large p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Grid View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Category View" href="{% url 'libraries-by-category' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-cat p-[10px] bg-gray-100 dark:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Category View</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{# Select a version #}
|
||||
<div class="grow">
|
||||
<select onchange="this.form.submit()"
|
||||
name="version"
|
||||
class="dropdown py-2 md:block h-[38px] ml-3 md:ml-0 "
|
||||
id="id_version">
|
||||
{% for v in versions %}
|
||||
<option value="{{ v.slug }}" {% if version == v %}selected="selected"{% endif %}>{{ v.display_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% include "libraries/includes/library_preferences.html" %}
|
||||
|
||||
{# alert for non-current Boost versions #}
|
||||
{% include "libraries/includes/version_alert.html" %}
|
||||
|
||||
@@ -33,61 +33,7 @@
|
||||
{% endcomment %}
|
||||
</div>
|
||||
|
||||
<div class="mx-3 md:mx-0 pt-2 px-0 mb-2 text-right md:mb-2">
|
||||
|
||||
<form action="." method="get">
|
||||
<div class="flex relative space-x-3 justify-start">
|
||||
{# Search #}
|
||||
{% comment %} {% include "libraries/includes/search_input.html" %} {% endcomment %}
|
||||
|
||||
{# Display options #}
|
||||
<div class="flex space-x-3">
|
||||
<div class="relative group">
|
||||
<a title="Name View" href="{% url 'libraries-mini' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-list p-[10px] bg-gray-100 dark:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">List View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Grid View" href="{% url 'libraries' %}?reset_view=1"><i class="link rounded border border-gray-300 cursor-pointer fas fa-th-large p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Grid View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Category View" href="{% url 'libraries-by-category' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-cat p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Category View</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
|
||||
{# Select a category #}
|
||||
<div>
|
||||
{# todo: if someone selects a category and hits back, it retains their choice here. #}
|
||||
<select onchange="this.form.submit()"
|
||||
name="category"
|
||||
class="block py-2 pr-11 pl-5 mb-3 w-full text-sm bg-white rounded-md border border-gray-300 cursor-pointer sm:inline-block md:mb-0 ml-3 md:ml-0 md:w-auto dark:bg-black dark:border-slate"
|
||||
id="id_category"
|
||||
>
|
||||
<option value="">Filter by category</option>
|
||||
{% for c in categories %}
|
||||
<option value="{{ c.slug }}" {% if category == c %}selected="selected"{% endif %}>{{ c.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
{# Select a version #}
|
||||
<div class="grow">
|
||||
<select onchange="this.form.submit()"
|
||||
name="version"
|
||||
class="dropdown py-2 ml-auto md:block h-[38px]"
|
||||
id="id_version">
|
||||
{% for v in versions %}
|
||||
<option value="{{ v.slug }}" {% if version == v %}selected="selected"{% endif %}>{{ v.display_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% include "libraries/includes/library_preferences.html" %}
|
||||
|
||||
{# alert for non-current Boost versions #}
|
||||
{% include "libraries/includes/version_alert.html" %}
|
||||
|
||||
59
templates/libraries/includes/library_preferences.html
Normal file
59
templates/libraries/includes/library_preferences.html
Normal file
@@ -0,0 +1,59 @@
|
||||
{% with request.resolver_match.view_name as view_name %}
|
||||
<div class="pt-2 px-0 mb-2 text-right md:mb-2 mx-3 md:mx-0">
|
||||
<form action="{{request.path}}" method="get">
|
||||
<div class="flex relative space-x-3 justify-start">
|
||||
{# Search #}
|
||||
|
||||
{% comment %} {% include "libraries/includes/search_input.html" %} {% endcomment %}
|
||||
|
||||
{# Display options #}
|
||||
<div class="flex space-x-3">
|
||||
<div class="relative group">
|
||||
<a title="Name View" href="{% url 'libraries-mini' %}{% if url_params %}?{{ request.GET.urlencode }}{% endif %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-list p-[10px] {% if view_name == 'libraries-mini' %}bg-gray-100 dark:bg-slate{% else %}hover:bg-gray-100 dark:hover:bg-slate{% endif %}"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">List View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Grid View" href="{% url 'libraries-grid' %}{% if url_params %}?{{ request.GET.urlencode }}{% endif %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-th-large p-[10px] {% if view_name == 'libraries-grid' %}bg-gray-100 dark:bg-slate{% else %}hover:bg-gray-100 dark:hover:bg-slate{% endif %}"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Grid View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Category View" href="{% url 'libraries-by-category' %}{% if url_params %}?{{ request.GET.urlencode }}{% endif %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-cat p-[10px] {% if view_name == 'libraries-by-category' %}bg-gray-100 dark:bg-slate{% else %}hover:bg-gray-100 dark:hover:bg-slate{% endif %}"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Category View</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
|
||||
{# Select a category #}
|
||||
{% if view_name != 'libraries-by-category' %}
|
||||
<div>
|
||||
{# todo: if someone selects a category and hits back, it retains their choice here. #}
|
||||
<select onchange="this.form.submit()"
|
||||
name="category"
|
||||
class="block py-2 pr-11 pl-5 mb-3 w-full text-sm bg-white rounded-md border border-gray-300 cursor-pointer sm:inline-block md:mb-0 ml-3 md:ml-0 md:w-auto dark:bg-black dark:border-slate"
|
||||
id="id_category"
|
||||
>
|
||||
<option value="">Filter by category</option>
|
||||
{% for c in categories %}
|
||||
<option value="{{ c.slug }}" {% if category == c %}selected="selected"{% endif %}>{{ c.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Select a version #}
|
||||
<div class="flex grow justify-end">
|
||||
<select onchange="this.form.submit()"
|
||||
name="version"
|
||||
class="dropdown py-2 md:block h-[38px] ml-3 md:ml-0"
|
||||
id="id_version">
|
||||
<option value="latest" {% if version == "latest" %}selected="selected"{% endif %}>Latest</option>
|
||||
{% for v in versions %}
|
||||
<option value="{{ v.slug }}" {% if version == v %}selected="selected"{% endif %}>{{ v.display_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endwith %}
|
||||
@@ -33,62 +33,7 @@
|
||||
{% endcomment %}
|
||||
</div>
|
||||
|
||||
<div class="mx-3 md:mx-0 pt-2 px-0 mb-2 text-right md:mb-2">
|
||||
|
||||
<form action="." method="get">
|
||||
<div class="flex relative space-x-3 justify-start">
|
||||
{# Search #}
|
||||
|
||||
{% comment %} {% include "libraries/includes/search_input.html" %} {% endcomment %}
|
||||
|
||||
{# Display options #}
|
||||
<div class="flex space-x-3">
|
||||
<div class="relative group">
|
||||
<a title="Name View" href="{% url 'libraries-mini' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-list p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">List View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Grid View" href="{% url 'libraries' %}?reset_view=1"><i class="link rounded border border-gray-300 cursor-pointer fas fa-th-large p-[10px] bg-gray-100 dark:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Grid View</span>
|
||||
</div>
|
||||
<div class="relative group">
|
||||
<a title="Category View" href="{% url 'libraries-by-category' %}"><i class="link rounded border border-gray-300 cursor-pointer fas fa-cat p-[10px] hover:bg-gray-100 dark:hover:bg-slate"></i></a>
|
||||
<span class="group-hover:opacity-100 transition-opacity bg-slate px-1 text-xs text-gray-100 rounded-sm absolute top-5 left-1/2 -translate-x-1/2 translate-y-full opacity-0 m-0 mx-auto w-auto">Category View</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div></div>
|
||||
|
||||
{# Select a category #}
|
||||
<div>
|
||||
{# todo: if someone selects a category and hits back, it retains their choice here. #}
|
||||
<select onchange="this.form.submit()"
|
||||
name="category"
|
||||
class="block py-2 pr-11 pl-5 mb-3 w-full text-sm bg-white rounded-md border border-gray-300 cursor-pointer sm:inline-block md:mb-0 md:w-auto ml-3 md:ml-0 dark:bg-black dark:border-slate"
|
||||
id="id_category"
|
||||
>
|
||||
<option value="">Filter by category</option>
|
||||
{% for c in categories %}
|
||||
<option value="{{ c.slug }}" {% if category == c %}selected="selected"{% endif %}>{{ c.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{# Select a version #}
|
||||
<div class="grow">
|
||||
<select onchange="this.form.submit()"
|
||||
name="version"
|
||||
class="dropdown py-2 ml-auto md:block h-[38px]"
|
||||
id="id_version">
|
||||
<option value="latest" {% if version == "latest" %}selected="selected"{% endif %}>Latest</option>
|
||||
{% for v in versions %}
|
||||
<option value="{{ v.slug }}" {% if version == v %}selected="selected"{% endif %}>{{ v.display_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% include "libraries/includes/library_preferences.html" %}
|
||||
|
||||
{# alert for non-current Boost versions #}
|
||||
{% include "libraries/includes/version_alert.html" %}
|
||||
|
||||
Reference in New Issue
Block a user