Skip to content

Commit

Permalink
Merge pull request #2971 from digitalfabrik/feature/global_link_list_…
Browse files Browse the repository at this point in the history
…performance

Add centralised link list in the network management
  • Loading branch information
MizukiTemma authored Sep 24, 2024
2 parents 127d22a + bb28096 commit 8a5eca4
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 81 deletions.
7 changes: 7 additions & 0 deletions integreat_cms/cms/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@
<i icon-name="layout-grid"></i>
{% translate "Admin Dashboard" %}
</a>
{% if perms.cms.view_broken_links %}
<a href="{% url 'linkcheck_landing' %}"
class="{% if current_menu_item == 'linkcheck' %} active{% endif %}">
<i icon-name="link"></i>
{% translate "Broken Links" %}
</a>
{% endif %}
{% if perms.cms.view_region %}
<a href="{% url 'regions' %}"
class="{% if current_menu_item == 'regions' %} active{% endif %}">
Expand Down
37 changes: 20 additions & 17 deletions integreat_cms/cms/templates/linkcheck/link_list_row.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
{% load model_tags %}
{% load widget_tweaks %}
{% load linkcheck_filters %}
{% object_translation_has_view_perm request.user url.region_links.0.content_object as show_source_link %}
{% load url_tags %}
{% object_translation_has_view_perm request.user content_object as show_source_link %}
<tbody class="hover:bg-gray-100">
<tr class="border-t border-gray-200 text-gray-800"
{% if url.id == view.kwargs.url_id %}id="replace-url"{% endif %}>
Expand Down Expand Up @@ -65,28 +66,30 @@
</a>
</div>
</td>
<td class="pr-2 max-w-[75px] sm:max-w-[100px] md:max-w-[100px] lg:max-w-[100px] xl:max-w-[150px] 2xl:max-w-[200px] 3xl:max-w-[260px] 4xl:max-w-[400px]"
title="{{ url.region_links.0.text }}">
<div class="table-cell-truncate">
<span class="table-cell-content">{{ url.region_links.0.text }}</span>
<a class="toggle-table-cell">
<i icon-name="chevron-down" class="more"></i>
<i icon-name="chevron-up" class="less"></i>
</a>
</div>
</td>
{% with link_text=url.region_links.0.text %}
<td class="pr-2 max-w-[75px] sm:max-w-[100px] md:max-w-[100px] lg:max-w-[100px] xl:max-w-[150px] 2xl:max-w-[200px] 3xl:max-w-[260px] 4xl:max-w-[400px]"
title="{{ link_text }}">
<div class="table-cell-truncate">
<span class="table-cell-content">{{ link_text }}</span>
<a class="toggle-table-cell">
<i icon-name="chevron-down" class="more"></i>
<i icon-name="chevron-up" class="less"></i>
</a>
</div>
</td>
{% endwith %}
<td class="pr-2 max-w-[75px] sm:max-w-[100px] md:max-w-[100px] lg:max-w-[100px] xl:max-w-[150px] 2xl:max-w-[200px] 3xl:max-w-[260px] 4xl:max-w-[400px]">
<div class="table-cell-truncate">
{% spaceless %}
<span class="table-cell-content">
{% if show_source_link %}
<a href="{{ url.region_links.0.content_object.backend_edit_link }}"
<a href="{{ content_object.backend_edit_link }}"
title="{% translate "Go to source" %}"
class="hover:underline">
<span>{{ url.region_links.0.content_object.title }}</span>
<span>{{ content_object.title }}</span>
</a>
{% else %}
<span>{{ url.region_links.0.content_object.title }}</span>
<span>{{ content_object.title }}</span>
{% endif %}
</span>
{% endspaceless %}
Expand All @@ -100,8 +103,8 @@
{{ url.region_links|length }}
</td>
<td class="text-right pr-4">
<a title="{% translate "Replace URL globally" %}"
href="{% url 'edit_url' url_id=url.id url_filter=view.kwargs.url_filter region_slug=request.region.slug %}{{ pagination_params }}#replace-url"
<a title="{% if request.region %}{% translate "Replace URL centrally in the current region" %}{% else %}{% translate "Replace URL globally in all the regions" %}{% endif %}"
href="{% url_for_current_region 'edit_url' request url_id=url.id url_filter=view.kwargs.url_filter %}{{ pagination_params }}#replace-url"
class="btn-icon">
<i icon-name="pen-square"></i>
</a>
Expand All @@ -112,7 +115,7 @@
<td colspan="10">
<div class="flex gap-2 p-2">
{% render_field edit_url_form.url|add_error_class:"border-red-500" type="url" form="edit-url-form" %}
<a href="{% url 'linkcheck' url_filter=view.kwargs.url_filter region_slug=request.region.slug %}{{ pagination_params }}"
<a href="{% url_for_current_region 'linkcheck' request url_filter=view.kwargs.url_filter %}{{ pagination_params }}"
class="btn btn-red">{% translate "Cancel" %}</a>
<button type="submit" form="edit-url-form" class="btn">
{% translate "Save" %}
Expand Down
24 changes: 13 additions & 11 deletions integreat_cms/cms/templates/linkcheck/links_by_filter.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{% extends "_base.html" %}
{% load i18n %}
{% load static %}
{% load linkcheck_filters %}
{% load url_tags %}
{% block content %}
<div class="flex flex-wrap justify-between gap-4">
<h1 class="heading">
Expand All @@ -21,34 +23,34 @@ <h1 class="heading">
{% endif %}
</h1>
{% if request.user.expert_mode %}
<a href="{% url 'search_and_replace_link' region_slug=request.region.slug %}"
<a href="{% url_for_current_region 'search_and_replace_link' request %}"
class="font-bold text-sm text-gray-800 flex items-center gap-1 mb-2 hover:underline">
<span><i icon-name="replace" class="align-top h-5"></i> {% translate "Search & replace" %}</span>
</a>
{% endif %}
</div>
<a href="{% if view.kwargs.url_filter == 'valid' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='valid' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'valid' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='valid' %}{{ pagination_params }}{% endif %}"
class="pr-2 {% if view.kwargs.url_filter == 'valid' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Valid" %}
<span class="{% if view.kwargs.url_filter == 'valid' %}text-gray-500 font-normal{% endif %}">
({{ number_valid_urls }})
</span>
</a>
<a href="{% if view.kwargs.url_filter == 'invalid' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='invalid' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'invalid' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='invalid' %}{{ pagination_params }}{% endif %}"
class="px-2 border-l-2 border-gray-500 {% if view.kwargs.url_filter == 'invalid' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Invalid" %}
<span class="{% if view.kwargs.url_filter == 'invalid' %}text-gray-500 font-normal{% endif %}">
({{ number_invalid_urls }})
</span>
</a>
<a href="{% if view.kwargs.url_filter == 'unchecked' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='unchecked' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'unchecked' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='unchecked' %}{{ pagination_params }}{% endif %}"
class="px-2 border-l-2 border-gray-500 {% if view.kwargs.url_filter == 'unchecked' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Unchecked" %}
<span class="{% if view.kwargs.url_filter == 'unchecked' %}text-gray-500 font-normal{% endif %}">
({{ number_unchecked_urls }})
</span>
</a>
<a href="{% if view.kwargs.url_filter == 'ignored' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='ignored' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'ignored' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='ignored' %}{{ pagination_params }}{% endif %}"
class="px-2 border-l-2 border-gray-500 {% if view.kwargs.url_filter == 'ignored' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Ignored" %}
<span class="{% if view.kwargs.url_filter == 'ignored' %}text-gray-500 font-normal{% endif %}">
Expand All @@ -57,7 +59,7 @@ <h1 class="heading">
</a>
{% if request.user.expert_mode %}
{% if LINKCHECK_EMAIL_ENABLED %}
<a href="{% if view.kwargs.url_filter == 'email' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='email' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'email' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='email' %}{{ pagination_params }}{% endif %}"
class="px-2 border-l-2 border-gray-500 {% if view.kwargs.url_filter == 'email' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Email links" %}
<span class="{% if view.kwargs.url_filter == 'email' %}text-gray-500 font-normal{% endif %}">
Expand All @@ -66,7 +68,7 @@ <h1 class="heading">
</a>
{% endif %}
{% if LINKCHECK_PHONE_ENABLED %}
<a href="{% if view.kwargs.url_filter == 'phone' %}#{% else %}{% url 'linkcheck' region_slug=request.region.slug url_filter='phone' %}{% if request.GET.size %}?size={{ request.GET.size }}{% endif %}{% endif %}"
<a href="{% if view.kwargs.url_filter == 'phone' %}#{% else %}{% url_for_current_region 'linkcheck' request url_filter='phone' %}{{ pagination_params }}{% endif %}"
class="px-2 border-l-2 border-gray-500 {% if view.kwargs.url_filter == 'phone' %}text-black font-bold cursor-default{% else %}bg-transparent hover:underline text-blue-500 hover:text-blue-600 cursor-pointer{% endif %}">
{% translate "Phone links" %}
<span class="{% if view.kwargs.url_filter == 'phone' %}text-gray-500 font-normal{% endif %}">
Expand Down Expand Up @@ -134,7 +136,7 @@ <h1 class="heading">
</thead>
<tbody>
{% for url in filtered_urls %}
{% include "linkcheck/link_list_row.html" %}
{% include "linkcheck/link_list_row.html" with content_object=url.region_links.0.content_object %}
{% empty %}
<tr>
<td colspan="6" class="px-4 py-3">
Expand Down Expand Up @@ -170,16 +172,16 @@ <h1 class="heading">
</option>
{% if view.kwargs.url_filter == 'ignored' %}
<option value="unignore"
data-bulk-action="{% url 'linkcheck' region_slug=request.region.slug url_filter=view.kwargs.url_filter %}{{ pagination_params }}">
data-bulk-action="{% url_for_current_region 'linkcheck' request url_filter=view.kwargs.url_filter %} {{ pagination_params }}">
{% translate "Unignore" %}
</option>
{% else %}
<option value="recheck"
data-bulk-action="{% url 'linkcheck' region_slug=request.region.slug url_filter=view.kwargs.url_filter %}{{ pagination_params }}">
data-bulk-action="{% url_for_current_region 'linkcheck' request url_filter=view.kwargs.url_filter %} {{ pagination_params }}">
{% translate "Recheck" %}
</option>
<option value="ignore"
data-bulk-action="{% url 'linkcheck' region_slug=request.region.slug url_filter=view.kwargs.url_filter %}{{ pagination_params }}">
data-bulk-action="{% url_for_current_region 'linkcheck' request url_filter=view.kwargs.url_filter %} {{ pagination_params }}">
{% translate "Ignore" %}
</option>
{% endif %}
Expand Down
1 change: 1 addition & 0 deletions integreat_cms/cms/templatetags/linkcheck_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.utils.safestring import mark_safe

if TYPE_CHECKING:

from linkcheck.models import Url

register = template.Library()
Expand Down
20 changes: 20 additions & 0 deletions integreat_cms/cms/templatetags/url_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

from django import template
from django.urls import reverse
from django.utils.safestring import mark_safe

if TYPE_CHECKING:
from typing import Any
from urllib.parse import ParseResult

from django.http import HttpRequest

register = template.Library()


Expand All @@ -32,3 +37,18 @@ def add_queries(url: str, key: str, value: str | int) -> str:

parsed_url = parsed_url._replace(query=urlencode(url_query, doseq=True))
return urlunparse(parsed_url)


@register.simple_tag
@mark_safe
def url_for_current_region(target: str, request: HttpRequest, **kwargs: Any) -> str:
"""
Return the url matching the target url name, region and other supplied slugs
:param target: The name of target url
:param request: The current request, used to check whether a region is given or not
:param kwargs: Other slugs passed as the keyword argument
"""
if request.region:
kwargs["region_slug"] = request.region.slug
return reverse(target, kwargs=kwargs)
34 changes: 34 additions & 0 deletions integreat_cms/cms/urls/protected.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,40 @@
dashboard.AdminDashboardView.as_view(),
name="admin_dashboard",
),
path(
"linkcheck/",
include(
[
path(
"",
linkcheck.LinkcheckRedirectView.as_view(),
name="linkcheck_landing",
),
path(
"<slug:url_filter>/",
include(
[
path(
"",
linkcheck.LinkcheckListView.as_view(),
name="linkcheck",
),
path(
"<int:url_id>/",
linkcheck.LinkcheckListView.as_view(),
name="edit_url",
),
]
),
),
path(
"search_and_replace_link",
linkcheck.LinkReplaceView.as_view(),
name="search_and_replace_link",
),
]
),
),
path(
"regions/",
include(
Expand Down
13 changes: 10 additions & 3 deletions integreat_cms/cms/utils/linkcheck_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import DefaultDict, TYPE_CHECKING

from django.conf import settings
from django.db.models import Prefetch, Q, QuerySet, Subquery
from django.db.models import Count, Prefetch, Q, QuerySet, Subquery
from linkcheck import update_lock
from linkcheck.listeners import tasks_queue
from linkcheck.models import Link, Url
Expand Down Expand Up @@ -61,6 +61,12 @@ def get_urls(
)
)

# Annotate with number of links that are not ignored.
# If there is any link that is not ignored, the url is also not ignored.
urls = urls.annotate(
non_ignored_links=Count("links", filter=Q(links__ignore=False))
)

# Filter out ignored URL types
if settings.LINKCHECK_IGNORED_URL_TYPES:
return [
Expand Down Expand Up @@ -141,8 +147,9 @@ def filter_urls(
[] for _ in range(6)
)
for url in urls:
links = url.region_links if region_slug else url.links.all()
if all(link.ignore for link in links):
if region_slug is None:
url.region_links = url.links.all()
if not url.non_ignored_links:
ignored_urls.append(url)
elif url.status:
valid_urls.append(url)
Expand Down
10 changes: 7 additions & 3 deletions integreat_cms/cms/views/linkcheck/link_replace_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,13 @@ def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
_("Links were replaced successfully."),
)

if request.region:
return redirect(
"linkcheck_landing",
**{
"region_slug": request.region.slug,
},
)
return redirect(
"linkcheck_landing",
**{
"region_slug": request.region.slug,
},
)
Loading

0 comments on commit 8a5eca4

Please sign in to comment.