Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 90d720e

Browse files
authoredMar 20, 2024··
Add indexers for custom blocks (#21)
1 parent 3f50fc2 commit 90d720e

File tree

4 files changed

+156
-3
lines changed

4 files changed

+156
-3
lines changed
 

‎setup.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""Installer for the nswdesignsystem.plone6 package."""
22

3-
from setuptools import find_packages
4-
from setuptools import setup
5-
3+
from setuptools import find_packages, setup
64

75
long_description = "\n\n".join(
86
[
@@ -64,6 +62,7 @@
6462
"collective.volto.formsupport[recaptcha]",
6563
"collective.volto.formsupport[honeypot]",
6664
"collective.volto.subfooter==1.1.0",
65+
"html2text", # Needed for adding blocks with HTML to the searchable text index
6766
],
6867
extras_require={
6968
"test": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<configure
2+
xmlns="http://namespaces.zope.org/zope"
3+
xmlns:i18n="http://namespaces.zope.org/i18n"
4+
xmlns:plone="http://namespaces.plone.org/plone"
5+
i18n_domain="nswdesignsystem.plone6"
6+
>
7+
8+
<!-- Covers the card block as we use cards as the replacement for the default grid in the frontend -->
9+
<adapter
10+
factory=".indexers.NSWSearchableText"
11+
name="__grid"
12+
/>
13+
<adapter
14+
factory=".indexers.NSWSearchableText"
15+
name="contentBlockGrid"
16+
/>
17+
18+
<adapter
19+
factory=".indexers.NSWSearchableText"
20+
name="callout"
21+
/>
22+
<adapter
23+
factory=".indexers.NSWSearchableText"
24+
name="nsw_inPageAlert"
25+
/>
26+
<adapter
27+
factory=".indexers.NSWSearchableText"
28+
name="nsw_announcementBar"
29+
/>
30+
<adapter
31+
factory=".indexers.NSWSearchableText"
32+
name="nsw_linkList"
33+
/>
34+
35+
<!-- TODO: Contribute back to core -->
36+
<adapter
37+
factory=".indexers.HeroSearchableText"
38+
name="hero"
39+
/>
40+
41+
</configure>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from html2text import HTML2Text
2+
from plone.restapi.behaviors import IBlocks
3+
from plone.restapi.interfaces import IBlockSearchableText
4+
from zope.component import adapter
5+
from zope.interface import implementer
6+
from zope.publisher.interfaces.browser import IBrowserRequest
7+
8+
html2text_extractor = HTML2Text()
9+
# Remove the extra characters from formatted text
10+
html2text_extractor.emphasis_mark = ""
11+
html2text_extractor.strong_mark = ""
12+
html2text_extractor.ul_item_mark = ""
13+
14+
15+
def get_rich_text_data(rich_text_field):
16+
data = (
17+
rich_text_field
18+
if isinstance(rich_text_field, str)
19+
else rich_text_field.get("data", "")
20+
)
21+
return html2text_extractor.handle(data)
22+
23+
24+
def extract_card(block_data):
25+
title = block_data.get("title", "")
26+
description = get_rich_text_data(block_data.get("description", ""))
27+
28+
return f"{title} {description}"
29+
30+
31+
def extract_content_block(block_data):
32+
title = block_data.get("title", "")
33+
description = get_rich_text_data(block_data.get("description", ""))
34+
35+
return f"{title} {description}"
36+
37+
38+
def extract_announcement_bar(block_data):
39+
return f"{get_rich_text_data(block_data.get('body', ''))}"
40+
41+
42+
def extract_callout(block_data):
43+
title = block_data.get("title", "")
44+
contents = get_rich_text_data(block_data.get("contents", ""))
45+
46+
return f"{title} {contents}"
47+
48+
49+
def extract_link_list(block_data):
50+
titles = []
51+
for link in block_data.get("links", []):
52+
link_info = link.get("url", {})
53+
if not link_info:
54+
continue
55+
link_info_data = link_info[0]
56+
if not isinstance(link_info_data, dict):
57+
continue
58+
title = link_info_data.get("title")
59+
if title:
60+
titles.append(title)
61+
return " ".join(titles)
62+
63+
64+
def extract_column_data(block_data):
65+
data = []
66+
67+
for column in block_data.get("columns", []):
68+
extractor = BLOCK_TYPE_EXTRACTOR_MAPPING[column["@type"]]
69+
if not extractor:
70+
continue
71+
data.append(extractor(column))
72+
73+
return " ".join(data)
74+
75+
76+
BLOCK_TYPE_EXTRACTOR_MAPPING = {
77+
"__grid": extract_column_data,
78+
"contentBlockGrid": extract_column_data,
79+
"card": extract_card,
80+
"contentBlock": extract_content_block,
81+
"nsw_announcementBar": extract_announcement_bar,
82+
"callout": extract_callout,
83+
"nsw_inPageAlert": extract_announcement_bar,
84+
"nsw_linkList": extract_link_list,
85+
}
86+
87+
88+
@implementer(IBlockSearchableText)
89+
@adapter(IBlocks, IBrowserRequest)
90+
class NSWSearchableText(object):
91+
def __init__(self, context, request):
92+
self.context = context
93+
self.request = request
94+
95+
def __call__(self, block_value):
96+
extractor = BLOCK_TYPE_EXTRACTOR_MAPPING[block_value["@type"]]
97+
if not extractor:
98+
return ""
99+
return extractor(block_value)
100+
101+
102+
@implementer(IBlockSearchableText)
103+
@adapter(IBlocks, IBrowserRequest)
104+
class HeroSearchableText(object):
105+
def __init__(self, context, request):
106+
self.context = context
107+
self.request = request
108+
109+
def __call__(self, block_value):
110+
title = block_value.get("title", "")
111+
description = block_value.get("description", "")
112+
return f"{title} {description}"

‎src/nswdesignsystem/plone6/configure.zcml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<include file="upgrades.zcml" />
1818
<include package=".browser" />
1919
<include package=".restapi" />
20+
<include package=".blocks" />
2021

2122
<include file="permissions.zcml" />
2223

0 commit comments

Comments
 (0)
Please sign in to comment.