mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-04-29 10:10:19 +00:00
views: Implement retrieving breadcrumbs of a page
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Veiko Aasa <veiko17@disroot.org>
This commit is contained in:
parent
86031d25f1
commit
a29fb97dd9
@ -3,13 +3,20 @@
|
|||||||
Django URL patterns for running tests.
|
Django URL patterns for running tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.urls import re_path
|
from django.urls import include, re_path
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
_test_view = TemplateView.as_view(template_name='index.html')
|
_test_view = TemplateView.as_view(template_name='index.html')
|
||||||
|
|
||||||
|
app_urls = [
|
||||||
|
re_path(r'^apps/testapp/$', _test_view, name='index'),
|
||||||
|
re_path(r'^apps/testapp/create/$', _test_view, name='create'),
|
||||||
|
]
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r'^$', _test_view, name='index'),
|
re_path(r'^$', _test_view, name='index'),
|
||||||
re_path(r'^apps/$', _test_view, name='apps'),
|
re_path(r'^apps/$', _test_view, name='apps'),
|
||||||
|
re_path(r'', include((app_urls, 'testapp'))),
|
||||||
re_path(r'^sys/$', _test_view, name='system'),
|
re_path(r'^sys/$', _test_view, name='system'),
|
||||||
re_path(r'^test/(?P<a>\d+)/(?P<b>\d+)/(?P<c>\d+)/$', _test_view,
|
re_path(r'^test/(?P<a>\d+)/(?P<b>\d+)/(?P<c>\d+)/$', _test_view,
|
||||||
name='test'),
|
name='test'),
|
||||||
|
|||||||
@ -4,8 +4,69 @@ Tests for common FreedomBox views.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from django.urls import resolve
|
||||||
|
|
||||||
from plinth.views import is_safe_url
|
from plinth import menu as menu_module
|
||||||
|
from plinth.views import get_breadcrumbs, is_safe_url
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name='menu')
|
||||||
|
def fixture_menu():
|
||||||
|
"""Initialized menu module."""
|
||||||
|
menu_module.Menu._all_menus = set()
|
||||||
|
menu_module.init()
|
||||||
|
menu_module.Menu('home-id', name='Home', url_name='index')
|
||||||
|
menu_module.Menu('apps-id', name='Apps', url_name='apps',
|
||||||
|
parent_url_name='index')
|
||||||
|
menu_module.Menu('testapp-id', name='Test App', url_name='testapp:index',
|
||||||
|
parent_url_name='apps')
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_breadcrumbs(rf, menu):
|
||||||
|
"""Test that computing breadcrumbs works."""
|
||||||
|
|
||||||
|
def _crumb(name: str, is_active: bool = False, url_name: str | None = None,
|
||||||
|
is_active_section: bool = False):
|
||||||
|
crumb = {'name': name, 'is_active': is_active, 'url_name': url_name}
|
||||||
|
if is_active_section:
|
||||||
|
crumb['is_active_section'] = True
|
||||||
|
|
||||||
|
return crumb
|
||||||
|
|
||||||
|
def _get(path: str):
|
||||||
|
request = rf.get(path)
|
||||||
|
request.resolver_match = resolve(path)
|
||||||
|
return get_breadcrumbs(request)
|
||||||
|
|
||||||
|
def _compare(dict1: dict[str, dict[str, str | bool]],
|
||||||
|
dict2: dict[str, dict[str, str | bool]]):
|
||||||
|
"""Compare dictionaries with order."""
|
||||||
|
assert list(dict1.items()) == list(dict2.items())
|
||||||
|
|
||||||
|
_compare(_get('/'), {'/': _crumb('Home', True, 'index', True)})
|
||||||
|
_compare(
|
||||||
|
_get('/apps/'), {
|
||||||
|
'/apps/': _crumb('Apps', True, 'apps', True),
|
||||||
|
'/': _crumb('Home', False, 'index'),
|
||||||
|
})
|
||||||
|
_compare(
|
||||||
|
_get('/apps/testapp/'), {
|
||||||
|
'/apps/testapp/': _crumb('Test App', True, 'testapp:index'),
|
||||||
|
'/apps/': _crumb('Apps', False, 'apps', True),
|
||||||
|
'/': _crumb('Home', False, 'index'),
|
||||||
|
})
|
||||||
|
_compare(
|
||||||
|
_get('/apps/testapp/create/'), {
|
||||||
|
'/apps/testapp/create/': _crumb('Here', True, 'testapp:create'),
|
||||||
|
'/apps/testapp/': _crumb('Test App', False, 'testapp:index'),
|
||||||
|
'/apps/': _crumb('Apps', False, 'apps', True),
|
||||||
|
'/': _crumb('Home', False, 'index'),
|
||||||
|
})
|
||||||
|
_compare(
|
||||||
|
_get('/test/1/2/3/'), {
|
||||||
|
'/test/1/2/3/': _crumb('Here', True, 'test', True),
|
||||||
|
'/': _crumb('Home', False, 'index'),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('url', [
|
@pytest.mark.parametrize('url', [
|
||||||
|
|||||||
@ -11,7 +11,8 @@ import urllib.parse
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.forms import Form
|
from django.forms import Form
|
||||||
from django.http import Http404, HttpResponseBadRequest, HttpResponseRedirect
|
from django.http import (Http404, HttpRequest, HttpResponseBadRequest,
|
||||||
|
HttpResponseRedirect)
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -62,6 +63,53 @@ def is_safe_url(url):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_breadcrumbs(request: HttpRequest) -> dict[str, dict[str, str | bool]]:
|
||||||
|
"""Return all the URL ancestors that can be show as breadcrumbs."""
|
||||||
|
breadcrumbs = {}
|
||||||
|
|
||||||
|
def _add(url: str, name: str, url_name: str | None = None):
|
||||||
|
"""Add item into the breadcrumb dictionary."""
|
||||||
|
breadcrumbs[url] = {
|
||||||
|
'name': name,
|
||||||
|
'is_active': request.path == url,
|
||||||
|
'url_name': url_name
|
||||||
|
}
|
||||||
|
|
||||||
|
url_name = request.resolver_match.url_name
|
||||||
|
full_url_name = ':'.join(request.resolver_match.app_names + [url_name])
|
||||||
|
try:
|
||||||
|
menu_item = menu.Menu.get_with_url_name(full_url_name)
|
||||||
|
except LookupError:
|
||||||
|
# There is no menu entry for this page, find it's app.
|
||||||
|
_add(request.path, _('Here'), full_url_name)
|
||||||
|
app_url_name = ':'.join(request.resolver_match.app_names + ['index'])
|
||||||
|
try:
|
||||||
|
menu_item = menu.Menu.get_with_url_name(app_url_name)
|
||||||
|
except LookupError:
|
||||||
|
# Don't know which app this page belongs to, assume parent is Home.
|
||||||
|
menu_item = menu.Menu.get_with_url_name('index')
|
||||||
|
|
||||||
|
for _number in range(10):
|
||||||
|
_add(menu_item.url, menu_item.name, menu_item.url_name)
|
||||||
|
if not menu_item.parent_url_name:
|
||||||
|
# We have reached the top
|
||||||
|
break
|
||||||
|
|
||||||
|
menu_item = menu.Menu.get_with_url_name(menu_item.parent_url_name)
|
||||||
|
else:
|
||||||
|
# Too much hierarchy, we must be in a recursive loop.
|
||||||
|
breadcrumbs = {}
|
||||||
|
menu_item = menu.Menu.get_with_url_name('index')
|
||||||
|
_add(menu_item.url, menu_item.name, menu_item.url_name)
|
||||||
|
|
||||||
|
# Find the active section: 'index', 'apps', 'system' or 'help'.
|
||||||
|
active_section_index = -2 if len(breadcrumbs) >= 2 else -1
|
||||||
|
active_section_key = list(breadcrumbs.keys())[active_section_index]
|
||||||
|
breadcrumbs[active_section_key]['is_active_section'] = True
|
||||||
|
|
||||||
|
return breadcrumbs
|
||||||
|
|
||||||
|
|
||||||
def messages_error(request, message, exception):
|
def messages_error(request, message, exception):
|
||||||
"""Show an error message using Django messages framework.
|
"""Show an error message using Django messages framework.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user