Skip to content

Commit

Permalink
Improve blocks SearchableText indexing (#118)
Browse files Browse the repository at this point in the history
* Add more block indexers for SearchableText.

* code cleanup

* fix upgrade-step

* fix reindex method in upgrade-step

* Add indexer for count_down block

* zpretty

* improve reindex on upgrade-step to reindex only contents with some blocks
  • Loading branch information
cekk authored Oct 17, 2024
1 parent 2a64ac2 commit dbade89
Show file tree
Hide file tree
Showing 7 changed files with 855 additions and 35 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Changelog

- Remove dependency with *collective.volto.cookieconsent*.
[cekk]

- Add more block indexers for SearchableText.
[cekk]

5.5.5 (2024-09-23)
------------------
Expand Down
198 changes: 171 additions & 27 deletions src/redturtle/volto/indexers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
from plone.app.contenttypes.interfaces import IEvent
from plone.dexterity.interfaces import IDexterityContent
from plone.indexer.decorator import indexer
from plone.restapi.indexers import extract_text
from plone.restapi.interfaces import IBlockSearchableText
from Products.CMFPlone.utils import safe_unicode
from zope.component import adapter
from zope.interface import implementer
from zope.publisher.interfaces.browser import IBrowserRequest


try:
from plone.base.utils import safe_text
except ImportError:
# Plone5 compatibility
from Products.CMFPlone.utils import safe_unicode as safe_text


@indexer(IEvent)
def open_end(obj):
""" """
Expand All @@ -28,21 +35,61 @@ def recurrence(obj):


def _extract_text(block_data):
"""both slate and draftjs support"""

if isinstance(block_data, str):
return block_data

result = ""
for paragraph in block_data.get("blocks", {}):
text = paragraph["text"]
result = " ".join((result, text))
return safe_unicode(result.strip())
if isinstance(block_data, dict):
# draftjs
for paragraph in block_data.get("blocks", {}):
text = paragraph["text"]
result = " ".join((result, text))
if isinstance(block_data, list):
result = " ".join(map(recursive_slate_text, block_data))
return safe_text(result.strip())


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class AccordionBlockSearchableText:
def recursive_slate_text(paragraph):
text = [paragraph.get("text", "")]
children = paragraph.get("children", {})

for child in children:
child_text = recursive_slate_text(paragraph=child)
if child_text:
text.append(child_text)
return "".join(text)


# SearchableText indexers for blocks


class BaseBlockSearchableText:
def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self, value):
text = []
# base fields
text.append(_extract_text(value.get("text", {})))
text.append(_extract_text(value.get("title", {})))
text.append(_extract_text(value.get("description", {})))

# extra fields
text.append(self.get_extra_text(value=value))
text = " ".join(text)
return safe_text(text.strip())

def get_extra_text(self, value):
return ""


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class AccordionBlockSearchableText(BaseBlockSearchableText):
def get_extra_text(self, value):
text = []
for subblock in value.get("subblocks", []):
text.append(_extract_text(subblock.get("text", {})))
Expand All @@ -52,23 +99,14 @@ def __call__(self, value):

@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class AlertBlockSearchableText:
def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self, value):
return _extract_text(value.get("text", {}))
class AlertBlockSearchableText(BaseBlockSearchableText):
"""Alert block"""


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class SimpleCardBlockSearchableText:
def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self, value):
class SimpleCardBlockSearchableText(BaseBlockSearchableText):
def get_extra_text(self, value):
return " ".join(
(
_extract_text(value.get("simple_card_title", {})),
Expand All @@ -79,15 +117,121 @@ def __call__(self, value):

@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class CardWithImageBlockSearchableText:
def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self, value):
class CardWithImageBlockSearchableText(BaseBlockSearchableText):
def get_extra_text(self, value):
return " ".join(
(
_extract_text(value.get("image_card_title", {})),
_extract_text(value.get("image_card_content", {})),
)
)


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class CalloutBlockSearchableText(BaseBlockSearchableText):
"""Callout"""


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class HeroBlockSearchableText(BaseBlockSearchableText):
"""Hero"""


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class CTABlockSearchableText(BaseBlockSearchableText):
"""Call to action block"""

def get_extra_text(self, value):
return " ".join(
(
_extract_text(value.get("cta_title", {})),
_extract_text(value.get("cta_content", {})),
)
)


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class GridBlockSearchableText(BaseBlockSearchableText):
"""grid block"""

def get_extra_text(self, value):
blocks_text = []
for block in value.get("blocks", {}).values():
blocks_text.append(
extract_text(block=block, obj=self.context, request=self.request)
)
return " ".join(blocks_text)


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class SlateTableBlockSearchableText(BaseBlockSearchableText):
"""slate table"""

def get_extra_text(self, value):
table_text = []
for row in value.get("table", {}).get("rows", []):
for cell in row.get("cells", []):
table_text.append(_extract_text(cell.get("value", {})))

return " ".join(table_text)


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class ContactsBlockSearchableText(BaseBlockSearchableText):
"""contacts"""

def get_extra_text(self, value):
text = []
for subblock in value.get("subblocks", []):
text.append(_extract_text(subblock.get("text", {})))
text.append(_extract_text(subblock.get("title", {})))
text.append(_extract_text(subblock.get("tel", {})))
text.append(_extract_text(subblock.get("email", {})))
return " ".join([s for s in text])


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class IconBlockSearchableText(BaseBlockSearchableText):
"""icons"""

def get_extra_text(self, value):
text = []
for subblock in value.get("subblocks", []):
text.append(_extract_text(subblock.get("text", {})))
text.append(_extract_text(subblock.get("title", {})))
return " ".join([s for s in text])


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class NumbersBlockSearchableText(BaseBlockSearchableText):
"""numbers"""

def get_extra_text(self, value):
text = []
for subblock in value.get("subblocks", []):
text.append(_extract_text(subblock.get("text", {})))
text.append(_extract_text(subblock.get("title", {})))
return " ".join([s for s in text])


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class RemoteCounterBlockSearchableText(BaseBlockSearchableText):
"""reomte counter"""


@implementer(IBlockSearchableText)
@adapter(IDexterityContent, IBrowserRequest)
class CountDownBlockSearchableText(BaseBlockSearchableText):
"""count-down block"""

def get_extra_text(self, value):
return " ".join((_extract_text(value.get("countdown_text", {})),))
41 changes: 40 additions & 1 deletion src/redturtle/volto/indexers.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,45 @@
factory=".indexers.CardWithImageBlockSearchableText"
name="testo_riquadro_immagine"
/>

<adapter
factory=".indexers.CalloutBlockSearchableText"
name="callout_block"
/>
<adapter
factory=".indexers.HeroBlockSearchableText"
name="hero"
/>
<adapter
factory=".indexers.CTABlockSearchableText"
name="cta_block"
/>
<adapter
factory=".indexers.GridBlockSearchableText"
name="gridBlock"
/>
<adapter
factory=".indexers.SlateTableBlockSearchableText"
name="slateTable"
/>
<adapter
factory=".indexers.ContactsBlockSearchableText"
name="contacts"
/>
<adapter
factory=".indexers.IconBlockSearchableText"
name="iconBlocks"
/>
<adapter
factory=".indexers.NumbersBlockSearchableText"
name="numbersBlock"
/>
<adapter
factory=".indexers.RemoteCounterBlockSearchableText"
name="remote-counter"
/>
<adapter
factory=".indexers.CountDownBlockSearchableText"
name="count_down"
/>

</configure>
2 changes: 1 addition & 1 deletion src/redturtle/volto/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<version>4307</version>
<version>4308</version>
<dependencies>
<dependency>profile-plone.volto:default</dependency>
<dependency>profile-plone.app.caching:with-caching-proxy</dependency>
Expand Down
Loading

0 comments on commit dbade89

Please sign in to comment.