Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add centralised link list in the network management #2971

Merged
merged 1 commit into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading