Skip to content

Commit

Permalink
Suggest users potential contacts
Browse files Browse the repository at this point in the history
Co-authored-by: JoeyStk <[email protected]>
  • Loading branch information
MizukiTemma and JoeyStk committed Jan 23, 2025
1 parent 7d703ab commit 72869da
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{% extends "_base.html" %}
{% load i18n %}
{% load static %}
{% block content %}
<div class="flex justify-between mb-4">
<h1 class="heading">
{% translate "Potential contact data" %}
</h1>
</div>
<div class="pb-4">
<span class="pb-4">
{% translate "Here is the list of E-mail addresses and phone numbers that are embedded in contents. We recommend to replace them with a contact card so they can be centrally managed and updated in future." %}
</span>
</div>
<div class="pb-4">
<div class="pb-4">
<h2 class="font-bold">
{% translate "Pages" %}
</h2>
{% if links_per_page %}
{{ links_per_page|length }}{% translate " pages have potential contacts." %}
{% endif %}
</div>
{% for content, links, contacts in links_per_page %}
{% include "contacts/contact_from_email_and_phone_row.html" with collapsed=True %}
{% empty %}
{% translate "No E-mail address and phone number detected" %}
{% endfor %}
</div>
<div class="pb-4">
<div class="pb-4">
<h2 class="font-bold">
{% translate "Events" %}
</h2>
{% if links_per_event %}
{{ links_per_event|length }}{% translate " events have potential contacts." %}
{% endif %}
</div>
{% for content, links, contacts in links_per_event %}
{% include "contacts/contact_from_email_and_phone_row.html" with collapsed=True %}
{% empty %}
{% translate "No E-mail address and phone number detected" %}
{% endfor %}
</div>
<div class="pb-4">
<div class="pb-4">
<h2 class="font-bold">
{% translate "Locations" %}
</h2>
{% if links_per_poi %}
{{ links_per_poi|length }}{% translate " events have potential contacts." %}
{% endif %}
</div>
{% for content, links, contacts in links_per_poi %}
{% include "contacts/contact_from_email_and_phone_row.html" with collapsed=True %}
{% empty %}
{% translate "No E-mail address and phone number detected" %}
{% endfor %}
</div>
{% include "pagination.html" with chunk=contacts %}
{% endblock content %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{% extends "../_collapsible_box.html" %}
{% load i18n %}
{% load content_filters %}
{% load page_filters %}
{% load tree_filters %}
{% load static %}
{% load rules %}
{% block collapsible_box_icon %}
{% endblock collapsible_box_icon %}
{% block collapsible_box_title %}
{{ content.best_translation.title }}
<i icon-name="eye"></i> <a href="{{ content.backend_edit_link }}"><i icon-name="pencil"></i></a>
{% endblock collapsible_box_title %}
{% block collapsible_box_content %}
<div class="grid xl:grid-cols-2 gap-4">
<div>
{% for link in links %}
<div>
{{ link }}
<a class="underline"
href="{% url 'new_contact' region_slug=request.region.slug %}?link={{ link }}">{% translate "Convert to contact" %}</a>
</div>
{% endfor %}
</div>
<div>
{% for contact in contacts %}
<div>
{{ contact }}
</div>
{% empty %}
{% trans "There is no contact suggested." %}
{% endfor %}
</div>
</div>
{% endblock collapsible_box_content %}
34 changes: 20 additions & 14 deletions integreat_cms/cms/templates/contacts/contact_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,27 @@ <h1 class="heading">
{% translate "Contacts" %}
{% endif %}
</h1>
{% if is_archive %}
<a href="{% url 'contacts' region_slug=request.region.slug %}"
class="font-bold text-sm text-gray-800 flex items-center gap-1 mb-2 hover:underline">
<span><i icon-name="book-open" class="align-top h-5"></i> {% translate "Back to contacts" %}</span>
<div class="flex">
<a href="{% url 'potential_targets' region_slug=request.region.slug %}"
class="font-bold text-sm text-gray-800 flex items-center gap-1 mb-2 hover:underline mr-2">
<i icon-name="lightbulb" class="align-baseline"></i>{% trans "Analysis of content for existing contacts" %}
</a>
{% else %}
<a href="{% url 'archived_contacts' region_slug=request.region.slug %}"
class="font-bold text-sm text-gray-800 flex items-center pb-3 hover:underline">
<span>
<i icon-name="archive" class="align-top h-5"></i>
{% translate "Archived contacts" %}
({{ archived_count }})
</span>
</a>
{% endif %}
{% if is_archive %}
<a href="{% url 'contacts' region_slug=request.region.slug %}"
class="font-bold text-sm text-gray-800 flex items-center gap-1 mb-2 hover:underline">
<span><i icon-name="book-open" class="align-top h-5"></i> {% translate "Back to contacts" %}</span>
</a>
{% else %}
<a href="{% url 'archived_contacts' region_slug=request.region.slug %}"
class="font-bold text-sm text-gray-800 flex items-center pb-3 hover:underline">
<span>
<i icon-name="archive" class="align-top h-5"></i>
{% translate "Archived contacts" %}
({{ archived_count }})
</span>
</a>
{% endif %}
</div>
</div>
<div class="flex flex-wrap justify-end gap-4">
{% if perms.cms.change_contact %}
Expand Down
5 changes: 5 additions & 0 deletions integreat_cms/cms/urls/protected.py
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,11 @@
]
),
),
path(
"potential_targets",
contacts.PotentialContactSourcesView.as_view(),
name="potential_targets",
),
]
),
),
Expand Down
19 changes: 19 additions & 0 deletions integreat_cms/cms/utils/link_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from __future__ import annotations

import re
from typing import TYPE_CHECKING
from urllib.parse import ParseResult, unquote, urlparse

if TYPE_CHECKING:
from linkcheck.models import Url


def fix_domain_encoding(url: re.Match[str]) -> str:
"""
Expand All @@ -24,3 +28,18 @@ def fix_content_link_encoding(content: str) -> str:
:return: The fixed content
"""
return re.sub(r"(?<=[\"'])(https?://.+?)(?=[\"'])", fix_domain_encoding, content)


def clean_url(url: Url) -> str:
"""
Remove the prefix tel: and mailto:
:param url: The URL object
:return: URL string without prefix
"""

if url.type == "phone":
return url.url.lstrip("tel:")
if url.type == "mailto":
return url.url[7:]
return url.url
1 change: 1 addition & 0 deletions integreat_cms/cms/views/contacts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
RestoreContactBulkAction,
)
from .contact_form_view import ContactFormView
from .contact_from_existing_data import PotentialContactSourcesView
from .contact_list_view import ContactListView
3 changes: 3 additions & 0 deletions integreat_cms/cms/views/contacts/contact_form_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
:param \**kwargs: The supplied keyword arguments
:return: The rendered template response
"""
link = request.GET.get("link", None)
region = request.region
contact_instance = Contact.objects.filter(
id=kwargs.get("contact_id"), location__region=region
Expand Down Expand Up @@ -107,6 +108,8 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
else None
)

contact_form.fields["phone_number"].initial = link if link else None

return render(
request,
self.template_name,
Expand Down
134 changes: 134 additions & 0 deletions integreat_cms/cms/views/contacts/contact_from_existing_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.shortcuts import render
from django.views.generic.base import TemplateView

from integreat_cms.cms.utils.link_utils import clean_url

from ...models import Contact, Event, Page, POI
from ...utils.linkcheck_utils import get_region_links

if TYPE_CHECKING:
from typing import Any

from django.http import HttpRequest, HttpResponse
from django.template.response import TemplateResponse


class PotentialContactSourcesView(TemplateView):
# pylint: disable=too-many-locals
"""
View for the contact suggestion
"""

template_name = "contacts/contact_from_email_and_phone.html"
extra_context = {
"current_menu_item": "contacts",
}

def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> TemplateResponse:
r"""
Render the contact suggestion
:param request: Object representing the user call
:param \*args: The supplied arguments
:param \**kwargs: The supplied keyword arguments
:return: The rendered template response
"""

region_links = get_region_links(request.region)
email_or_phone_links = region_links.filter(
Q(url__url__startswith="mailto") | Q(url__url__startswith="tel")
)

page_translation_content_type_id = ContentType.objects.get(
model="pagetranslation"
).id
event_translation_content_type_id = ContentType.objects.get(
model="eventtranslation"
).id
poi_translation_content_type_id = ContentType.objects.get(
model="poitranslation"
).id

links_in_pages = email_or_phone_links.filter(
content_type=page_translation_content_type_id
)
links_in_events = email_or_phone_links.filter(
content_type=event_translation_content_type_id
)
links_in_pois = email_or_phone_links.filter(
content_type=poi_translation_content_type_id
)

page_ids = (
links_in_pages.order_by()
.values_list("page_translation__page", flat=True)
.distinct()
)
links_per_page = []
for page_id in page_ids:
page = Page.objects.filter(id=page_id).first()
links = [
clean_url(link.url)
for link in links_in_pages.filter(page_translation__page=page_id)
.order_by()
.distinct("url__url")
]
contacts = Contact.objects.filter(
Q(email__in=links) | Q(phone_number__in=links)
)
links_per_page += [(page, links, contacts)]

event_ids = (
links_in_events.order_by()
.values_list("event_translation__event", flat=True)
.distinct()
)
links_per_event = []
for event_id in event_ids:
event = Event.objects.filter(id=event_id).first()
links = [
clean_url(link.url)
for link in links_in_events.filter(event_translation__event=event_id)
.order_by()
.distinct("url__url")
]
contacts = Contact.objects.filter(
Q(email__in=links) | Q(phone_number__in=links)
)
links_per_event += [(event, links, contacts)]

poi_ids = (
links_in_pois.order_by()
.values_list("poi_translation__poi", flat=True)
.distinct()
)
links_per_poi = []
for poi_id in poi_ids:
poi = POI.objects.filter(id=poi_id).first()
links = [
clean_url(link.url)
for link in links_in_pois.filter(poi_translation__poi=poi_id)
.order_by()
.distinct("url__url")
]
contacts = Contact.objects.filter(
Q(email__in=links) | Q(phone_number__in=links)
)
links_per_poi += [(poi, links, contacts)]

return render(
request,
self.template_name,
{
**self.get_context_data(**kwargs),
"links_per_page": links_per_page,
"links_per_event": links_per_event,
"links_per_poi": links_per_poi,
},
)
Loading

0 comments on commit 72869da

Please sign in to comment.