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 view that lists all links in a tool #781

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
3 changes: 3 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Changelog
[reinhardt]
- Support openpyxl 3.x
[reinhardt]
- List links in tool
(`#2757 <https://github.com/syslabcom/scrum/issues/2757>`_)
[reinhardt]


16.2.5 (2024-12-09)
Expand Down
9 changes: 9 additions & 0 deletions src/euphorie/content/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,13 @@
layer="plonetheme.nuplone.skin.interfaces.NuPloneSkin"
/>

<browser:page
name="list-links"
for="euphorie.content.survey.ISurvey"
class=".survey.ListLinks"
template="templates/list-links.pt"
permission="euphorie.content.ManageCountry"
layer="plonetheme.nuplone.skin.interfaces.NuPloneSkin"
/>

</configure>
50 changes: 50 additions & 0 deletions src/euphorie/content/browser/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
from zope.event import notify
from zope.i18n import translate

import re


class SurveyBase(BrowserView):
def _morph(self, child):
Expand Down Expand Up @@ -520,3 +522,51 @@ def tools(self):
# we're done if we found at least one measure
break
return tools


class ListLinks(BrowserView):
attributes_checked = [
"description",
"introduction",
"solution_direction",
"legal_reference",
"action",
"action_plan",
"prevention_plan",
"requirements",
]
Comment on lines +528 to +537
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure these are all the fields in all relevant content types?
You could dynamically get all text fields and iterate over them. See how collective.searchandreplace does it. Ignore the Archetypes-related code. ;-)

url_regex = re.compile(
r"https?://[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b"
r"(?:[-a-zA-Z0-9()@:%_+.~#?&/=]*)"
)
Comment on lines +538 to +541
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably fine. Alternative idea: look for contents of href/src, so ="http...", with at the dots anything except a double quote or a space. Something like this:

>>> re.compile(r'="(https?://[^ "]*)"').match('="https://some.url"').groups()
('https://some.url',)


def extract_links(self, obj):
links = []
for attrib in self.attributes_checked:
value = getattr(aq_base(obj), attrib, "")
if value:
links.extend(self.url_regex.findall(value))
if links:
yield {
"object": obj,
"links": [{"url": link, "text": link} for link in links],
}
if hasattr(obj, "objectValues"):
for child in obj.objectValues():
Comment on lines +554 to +555
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically objectValues can contain non-contentish items, for example an object for local workflow policies. If I want only content I prefer contentValues:

Suggested change
if hasattr(obj, "objectValues"):
for child in obj.objectValues():
if hasattr(obj, "contentValues"):
for child in obj.contentValues():

for link in self.extract_links(child):
yield link

@property
def items(self):
"""Retrieves subobjects (modules, risks, etc.) which contain links.
Returns a list of dictionaries like this:
[
{
"object": self.context.objectValues()[0],
"links": [
{"url": "https://example.org/test", "text": "Example link"},
],
}
]
"""
return self.extract_links(self.context)
35 changes: 35 additions & 0 deletions src/euphorie/content/browser/templates/list-links.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
xmlns:meta="http://xml.zope.org/namespaces/meta"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:tal="http://xml.zope.org/namespaces/tal"
meta:interpolation="true"
metal:use-macro="context/@@layout/macros/layout"
i18n:domain="nuplone"
>

<metal:title fill-slot="title">List of Links in ${context/title}</metal:title>
<metal:content fill-slot="content">
<article>
<dl>
<tal:item tal:repeat="item view/items">
<dt tal:define="
obj python:item['object'];
">
<a href="${obj/absolute_url}">${obj/title}</a>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you suggest in the issue, I would say it is better to link to the edit form directly:

Suggested change
<a href="${obj/absolute_url}">${obj/title}</a>
<a href="${obj/absolute_url}/edit">${obj/title}</a>

</dt>
<dd tal:define="
links python:item['links'];
">
<ul>
<li tal:repeat="link links">
<a href="${link/url}">${link/text}</a>
</li>
</ul>
</dd></tal:item>
</dl>
</article>
</metal:content>
</html>
Loading