Skip to content
Open
7 changes: 7 additions & 0 deletions src/plone/volto/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@

<i18n:registerTranslations directory="locales" />

<include
package="Products.CMFCore"
file="permissions.zcml"
/>

<include file="dependencies.zcml" />
<include file="permissions.zcml" />

<include package=".behaviors" />
<include package=".browser" />
<include package=".indexers" />
<include package=".services" />

<include file="profiles.zcml" />
<include file="patches.zcml" />
Expand Down
6 changes: 4 additions & 2 deletions src/plone/volto/indexers/indexers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from plone.restapi.blocks import visit_blocks
from plone.volto.behaviors.preview import IPreview

import collections


@indexer(IPreview)
def hasPreviewImage(obj):
Expand Down Expand Up @@ -40,9 +42,9 @@ def image_field_indexer(obj):
def block_types_indexer(obj):
"""Indexer for all block types included in a page."""
obj = aq_base(obj)
block_types = set()
block_types = collections.Counter()
for block in visit_blocks(obj, obj.blocks):
block_type = block.get("@type")
if block_type:
block_types.add(block_type)
block_types[block_type] += 1
return block_types
8 changes: 8 additions & 0 deletions src/plone/volto/permissions.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<configure xmlns="http://namespaces.zope.org/zope">

<permission
id="plone.volto.service.BlockTypes"
title="Plone Site Setup: Block Types"
/>

</configure>
1 change: 1 addition & 0 deletions src/plone/volto/profiles/default/catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<column value="head_title" />
<column value="hasPreviewImage" />
<column value="image_field" />
<column value="block_types" />
Copy link
Member

Choose a reason for hiding this comment

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

We need an upgrade step for this

Copy link
Member Author

Choose a reason for hiding this comment

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

Since we modified an indexer here I guess we have to re-index the catalog, right? Is this what we would want:

<genericsetup:upgradeDepends
    title="Reindex block_types_indexer"
    profile="plone.volto:default"
    source="1019"
    destination="1020"
    import_steps="catalog"
  />

Copy link
Member

Choose a reason for hiding this comment

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

@jnptk yes, but...

We try to avoid upgrade steps which need to reindex all content, because it can take a long time in a large site. Actually for this reason, running the "catalog" import step updates the indexes and metadata but doesn't automatically reindex anything.

In this case we only have to reindex the items that provide IBlocks. So I think we should add a Python upgrade step which finds all blocks content (portal_catalog.unrestrictedSearchResults(object_provides=IBlocks.__identifier__)) and reindexes just the new index.

In case someone really wants to avoid it, they can run the upgrade steps in portal_setup where there is a checkbox to disable each step if needed.

We should mention this upgrade step in the release notes.

<index meta_type="KeywordIndex"
name="block_types"
>
Expand Down
2 changes: 1 addition & 1 deletion src/plone/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>1019</version>
<version>1020</version>
<dependencies>
<dependency>profile-plone.restapi:blocks</dependency>
</dependencies>
Expand Down
11 changes: 11 additions & 0 deletions src/plone/volto/profiles/default/rolemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<rolemap>
<permissions>
<permission acquire="True"
name="Plone Site Setup: Block Types"
>
<role name="Manager" />
<role name="Site Administrator" />
</permission>
</permissions>
</rolemap>
Empty file.
Empty file.
15 changes: 15 additions & 0 deletions src/plone/volto/services/blocktypes/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:zcml="http://namespaces.zope.org/zcml"
>

<plone:service
method="GET"
factory=".get.BlockTypesGet"
for="zope.interface.Interface"
permission="plone.volto.service.BlockTypes"
name="@blocktypes"
/>

</configure>
56 changes: 56 additions & 0 deletions src/plone/volto/services/blocktypes/get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from plone import api
from plone.restapi.behaviors import IBlocks
from plone.restapi.services import Service
from zope.interface import implementer
from zope.publisher.interfaces import IPublishTraverse

import collections


@implementer(IPublishTraverse)
class BlockTypesGet(Service):
def __init__(self, context, request):
super().__init__(context, request)
self.block_type = None

def publishTraverse(self, request, name):
self.block_type = name
return self

def reply(self):
catalog = api.portal.get_tool(name="portal_catalog")
request_body = self.request.form
type = self.block_type

query = {
"object_provides": IBlocks.__identifier__,
}

if request_body.get("path"):
query["path"] = request_body["path"]

if type:
result = []
query["block_types"] = self.block_type
brains = catalog.unrestrictedSearchResults(**query)

for brain in brains:
result.append(
{
"@id": brain.getURL(),
"title": brain.Title,
"count": brain.block_types[self.block_type],
}
)
else:
result = {}
brains = catalog.unrestrictedSearchResults(**query)
block_types_total = collections.Counter()

for brain in brains:
block_types_total.update(brain.block_types)

for block_type, count in block_types_total.items():
result[block_type] = count

Copy link
Member

Choose a reason for hiding this comment

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

To do: Add the code to get total counts for all blocks if type is None

Copy link
Member Author

Choose a reason for hiding this comment

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

@davisagli I've updated the code to return the block types + a total count when no specific block type is provided. e.g.:

{
  "slate": 22,
  "teaser": 1,
  "title": 3
}

also I changed that we don't return inside an "items" dict since we're very likely loading the items inside an "items" dict in the redux store, this way we can avoid having to access the items in the frontend like this: const items = useSelector((state) => state.blocktypes.items.items)

Copy link
Member Author

Choose a reason for hiding this comment

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

nvm. that was not a good idea, I'll handle that in the frontend via the action... 😅

Copy link
Member

Choose a reason for hiding this comment

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

Like we discussed this morning, I think it was a good idea after all :)

return result
8 changes: 8 additions & 0 deletions src/plone/volto/services/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:zcml="http://namespaces.zope.org/zcml"
>

<include package=".blocktypes" />

</configure>
13 changes: 13 additions & 0 deletions src/plone/volto/upgrades.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,16 @@ def update_robots_txt(context):
logger.info(
"Ignoring plone.robots_txt registry as it was modified in this portal."
)


def reindex_block_types(context):
catalog = getToolByName(context, "portal_catalog")
brains = catalog(object_provides="plone.restapi.behaviors.IBlocks")
total = len(brains)
for index, brain in enumerate(brains):
obj = brain.getObject()
obj.reindexObject(idxs=["block_types"], update_metadata=0)
logger.info("Reindexing object %s.", brain.getPath())
if index % 250 == 0:
logger.info(f"Reindexed {index}/{total} objects")
transaction.commit()
10 changes: 10 additions & 0 deletions src/plone/volto/upgrades.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,14 @@
handler=".upgrades.update_robots_txt"
/>
</genericsetup:upgradeSteps>
<genericsetup:upgradeSteps
profile="plone.volto:default"
source="1019"
destination="1020"
>
<genericsetup:upgradeStep
title="Update robots_txt setting for Volto"
handler=".upgrades.reindex_block_types"
/>
</genericsetup:upgradeSteps>
</configure>
Loading