Exemple #1
0
 def replace_filtered(self, data):
     occurences = parseItems(self.request["form.affectedContent"])
     occur_count = 0
     for page_url, page_result in occurences.items():
         for field, indexes in page_result.items():
             occur_count += len(indexes)
     srutil = getUtility(ISearchReplaceUtility)
     repl_count = srutil.replaceFilteredOccurences(
         self.context,
         data["findWhat"],
         replaceWith=data["replaceWith"],
         occurences=occurences,
         searchSubFolders=data.get("searchSubfolders", False),
         matchCase=data["matchCase"],
         onlySearchableText=data["onlySearchableText"],
     )
     IStatusMessage(self.request).addStatusMessage(
         _(
             u"Search text replaced in ${replaced} of ${items} "
             "instance(s).",
             mapping={
                 "replaced": repl_count,
                 "items": occur_count
             },
         ),
         type="info",
     )
class ISearchReplaceSettings(Interface):
    """Control panel settings for search and replace.
    """

    restrict_searchable_types = schema.Bool(
        title=_(u'Restrict the enabled types.'),
        description=_(
            u'If checked, only the enabled types are searched, '
            'otherwise all types are searched.'),
        required=False,
        default=False,
    )

    enabled_types = schema.List(
        title=_(u'List of types that are searched.'),
        description=_(
            u"When 'Restrict the enable types' is checked, "
            "only the selected types are searched. "
            "Otherwise this list is ignored."),
        value_type=schema.Choice(
            vocabulary='plone.app.vocabularies.PortalTypes',
        ),
        required=False,
        default=[
            'Collection',
            'Document',
            'Event',
            'File',
            'Folder',
            'Image',
            'News Item',
        ],
    )

    maximum_text_characters = schema.Int(
        title=_(u'Maximum text characters'),
        description=_(
            u'The maximum number of characters to show '
            'before and after the found text.'),
        required=False,
        default=50,
    )

    update_modified = schema.Bool(
        title=_(u'Update the modified datetime when replacing.'),
        description=_(
            u'If checked, the modified index/metadata of the object '
            u'having text replaced will be updated.'),
        required=False,
        default=True,
    )
Exemple #3
0
 def action_replace(self, action, data):
     """ Replace text for all files. """
     self.form_reset = False
     srutil = getUtility(ISearchReplaceUtility)
     if 'form.affectedContent' in self.request:
         # Do only the selected items
         # nitems = len(self.request['form.affectedContent'])
         items = srutil.parseItems(self.request['form.affectedContent'])
         nitems = 0
         for page_url, page_result in items.items():
             for field, indexes in page_result.items():
                 nitems += len(indexes)
         replaced = srutil.searchObjects(
             self.context,
             data['findWhat'],
             searchSubFolders=data.get('searchSubfolders', False),
             matchCase=data['matchCase'],
             replaceText=data['replaceWith'],
             doReplace=True,
             searchItems=items,
             onlySearchableText=data['onlySearchableText'],
         )
         IStatusMessage(self.request).addStatusMessage(
             _(u'Search text replaced in ${replaced} of ${items} '
               'instance(s).',
               mapping={'replaced': replaced, 'items': nitems}),
             type='info')
     else:
         # Do everything you can find
         replaced = srutil.searchObjects(
             self.context,
             data['findWhat'],
             searchSubFolders=data.get('searchSubfolders', False),
             matchCase=data['matchCase'],
             replaceText=data['replaceWith'],
             onlySearchableText=data['onlySearchableText'],
             doReplace=True)
         IStatusMessage(self.request).addStatusMessage(
             _(u'Search text replaced in all ${items} instance(s).',
               mapping={'items': replaced}),
             type='info')
Exemple #4
0
 def replace_all(self, data):
     srutil = getUtility(ISearchReplaceUtility)
     repl_count = srutil.replaceAllMatches(
         self.context,
         data["findWhat"],
         replaceWith=data["replaceWith"],
         searchSubFolders=data.get("searchSubfolders", False),
         matchCase=data["matchCase"],
         onlySearchableText=data["onlySearchableText"],
     )
     IStatusMessage(self.request).addStatusMessage(
         _(
             u"Search text replaced in all ${items} instance(s).",
             mapping={"items": repl_count},
         ),
         type="info",
     )
Exemple #5
0
    def _afterReplace(self, obj, find, rtext):
        """Hook for doing things after a text has been replaced.

        - obj is the changed object
        - find is the found text
        - rtext is the replacement text

        By default, we will store a version in the CMFEditions repository.
        """
        repository = getToolByName(obj, 'portal_repository', None)
        if repository is None:
            return
        if obj.portal_type not in repository.getVersionableContentTypes():
            return
        comment = _(u'Replaced: ${old} -> ${new}',
                    mapping={'old': find, 'new': rtext})
        comment = translate(comment, context=obj.REQUEST)
        repository.save(obj, comment=comment)
from collective.searchandreplace import SearchAndReplaceMessageFactory as _
from collective.searchandreplace.interfaces import ISearchReplaceSettings
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
from plone.app.registry.browser.controlpanel import RegistryEditForm
from plone.z3cform import layout
from z3c.form import form


class SearchReplaceControlPanelForm(RegistryEditForm):
    form.extends(RegistryEditForm)
    schema = ISearchReplaceSettings


SearchReplaceControlPanelView = layout.wrap_form(
    SearchReplaceControlPanelForm, ControlPanelFormWrapper
)
SearchReplaceControlPanelView.label = _(u"Search and Replace settings")
Exemple #7
0
class ISearchReplaceSettings(Interface):
    """Control panel settings for search and replace."""

    restrict_searchable_types = schema.Bool(
        title=_(u"Restrict the enabled types."),
        description=_(u"If checked, only the enabled types are searched, "
                      "otherwise all types are searched."),
        required=False,
        default=False,
    )

    enabled_types = schema.List(
        title=_(u"List of types that are searched."),
        description=_(u"When 'Restrict the enable types' is checked, "
                      "only the selected types are searched. "
                      "Otherwise this list is ignored."),
        value_type=schema.Choice(
            vocabulary="plone.app.vocabularies.PortalTypes", ),
        required=False,
        default=[
            "Collection",
            "Document",
            "Event",
            "File",
            "Folder",
            "Image",
            "News Item",
        ],
    )

    maximum_text_characters = schema.Int(
        title=_(u"Maximum text characters"),
        description=_(u"The maximum number of characters to show "
                      "before and after the found text."),
        required=False,
        default=50,
    )

    update_modified = schema.Bool(
        title=_(u"Update the modified datetime when replacing."),
        description=_(u"If checked, the modified index/metadata of the object "
                      u"having text replaced will be updated."),
        required=False,
        default=True,
    )

    include_textline_fields = schema.Bool(
        title=_(u"Search also textline fields"),
        description=_(
            u"If checked, single line fields "
            u"will also be searched and replaced, "
            u"not only title and text fields.", ),
        required=False,
        default=True,
    )

    include_lines_fields = schema.Bool(
        title=_(u"Search also lines fields"),
        description=_(
            u"If checked, multiple lines fields like subject "
            u"will also be searched and replaced, "
            u"not only title and text fields.", ),
        required=False,
        default=False,
    )
from collective.searchandreplace import SearchAndReplaceMessageFactory as _
from collective.searchandreplace.interfaces import ISearchReplaceSettings
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
from plone.app.registry.browser.controlpanel import RegistryEditForm
from plone.z3cform import layout
from z3c.form import form


class SearchReplaceControlPanelForm(RegistryEditForm):
    form.extends(RegistryEditForm)
    schema = ISearchReplaceSettings


SearchReplaceControlPanelView = layout.wrap_form(
    SearchReplaceControlPanelForm, ControlPanelFormWrapper)
SearchReplaceControlPanelView.label = _(u"Search and Replace settings")
Exemple #9
0
class SearchReplaceForm(AddForm):
    """ """
    @property
    def form_fields(self):
        form_fields = FormFields(ISearchReplaceForm)
        container = aq_parent(self.context)
        if not self.context.isPrincipiaFolderish and not isDefaultPage(
                container, self.context):
            form_fields = form_fields.omit("searchSubfolders")
        form_fields["findWhat"].custom_widget = TwoLineTextAreaWidget
        form_fields["replaceWith"].custom_widget = TwoLineTextAreaWidget
        return form_fields

    label = _(u"Search and Replace")
    description = _(u"Search and replace text found in documents.")
    template = ViewPageTemplateFile("pageform.pt")

    @action(_(u"Preview"), validator=None, name=u"Preview")
    def action_preview(self, action, data):
        """ Preview files to be changed. """
        self.form_reset = False

    @action(_(u"Replace"),
            validator=validate_searchreplaceform,
            name=u"Replace")
    def action_replace(self, action, data):
        """ Replace text for all files. """
        self.form_reset = False
        if "form.affectedContent" in self.request:
            self.replace_filtered(data)
        else:
            self.replace_all(data)

    def replace_filtered(self, data):
        occurences = parseItems(self.request["form.affectedContent"])
        occur_count = 0
        for page_url, page_result in occurences.items():
            for field, indexes in page_result.items():
                occur_count += len(indexes)
        srutil = getUtility(ISearchReplaceUtility)
        repl_count = srutil.replaceFilteredOccurences(
            self.context,
            data["findWhat"],
            replaceWith=data["replaceWith"],
            occurences=occurences,
            searchSubFolders=data.get("searchSubfolders", False),
            matchCase=data["matchCase"],
            onlySearchableText=data["onlySearchableText"],
        )
        IStatusMessage(self.request).addStatusMessage(
            _(
                u"Search text replaced in ${replaced} of ${items} "
                "instance(s).",
                mapping={
                    "replaced": repl_count,
                    "items": occur_count
                },
            ),
            type="info",
        )

    def replace_all(self, data):
        srutil = getUtility(ISearchReplaceUtility)
        repl_count = srutil.replaceAllMatches(
            self.context,
            data["findWhat"],
            replaceWith=data["replaceWith"],
            searchSubFolders=data.get("searchSubfolders", False),
            matchCase=data["matchCase"],
            onlySearchableText=data["onlySearchableText"],
        )
        IStatusMessage(self.request).addStatusMessage(
            _(
                u"Search text replaced in all ${items} instance(s).",
                mapping={"items": repl_count},
            ),
            type="info",
        )

    @action(_(u"Reset"), validator=None, name=u"Reset")
    def action_reset(self, action, data):
        """ Reset the form fields to their defaults. """
Exemple #10
0
class ISearchReplaceForm(Interface):
    """ Interface for Search and Replace form """

    findWhat = Text(title=_(u"Find What"),
                    description=_(u"Enter the text to find."),
                    required=True)

    replaceWith = Text(
        title=_(u"Replace With"),
        description=_(u"Enter the text to replace the original text with."),
        required=False,
    )

    maxResults = Int(
        title=_(u"Maximum Number of Results"),
        description=_(
            u"Maximum number of results to show. "
            "Warning: this has no effect on how many found texts are "
            "replaced when you use the Replace button directly without "
            "using the Preview."),
        default=None,
        required=False,
    )

    searchSubfolders = Bool(
        title=_(u"Search Subfolders"),
        description=_(u"If checked, this will recursively search "
                      "through any selected folders and their "
                      "children, replacing at each level."),
        default=True,
        required=True,
    )

    matchCase = Bool(
        title=_(u"Match Case"),
        description=_(u"Check the box for a case sensitive search."),
        default=False,
        required=True,
    )

    onlySearchableText = Bool(
        title=_(u"Fast search"),
        description=_(
            u"Use the catalog to search, just like the search form does. "
            "This only finds keywords, not html tags. "
            "You might have some text fields that are not found this way, "
            "so if not checked, you may find more content, "
            "but it will be slower. "
            "Regardless of this setting, when at least one match is found, "
            "text in all text fields may be replaced."),
        required=False,
        default=True,
    )
Exemple #11
0
class SearchReplaceForm(AddForm):
    """ """

    @property
    def form_fields(self):
        form_fields = FormFields(ISearchReplaceForm)
        container = aq_parent(self.context)
        if not self.context.isPrincipiaFolderish and not isDefaultPage(
                container, self.context):
            form_fields = form_fields.omit('searchSubfolders')
        form_fields['findWhat'].custom_widget = TwoLineTextAreaWidget
        form_fields['replaceWith'].custom_widget = TwoLineTextAreaWidget
        return form_fields

    label = _(u'Search and Replace')
    description = _(u'Search and replace text found in documents.')
    template = ViewPageTemplateFile('pageform.pt')

    @action(_(u'Preview'),
            validator=None,
            name=u'Preview')
    def action_preview(self, action, data):
        """ Preview files to be changed. """
        self.form_reset = False

    @action(_(u'Replace'),
            validator=validate_searchreplaceform,
            name=u'Replace')
    def action_replace(self, action, data):
        """ Replace text for all files. """
        self.form_reset = False
        srutil = getUtility(ISearchReplaceUtility)
        if 'form.affectedContent' in self.request:
            # Do only the selected items
            # nitems = len(self.request['form.affectedContent'])
            items = srutil.parseItems(self.request['form.affectedContent'])
            nitems = 0
            for page_url, page_result in items.items():
                for field, indexes in page_result.items():
                    nitems += len(indexes)
            replaced = srutil.searchObjects(
                self.context,
                data['findWhat'],
                searchSubFolders=data.get('searchSubfolders', False),
                matchCase=data['matchCase'],
                replaceText=data['replaceWith'],
                doReplace=True,
                searchItems=items,
                onlySearchableText=data['onlySearchableText'],
            )
            IStatusMessage(self.request).addStatusMessage(
                _(u'Search text replaced in ${replaced} of ${items} '
                  'instance(s).',
                  mapping={'replaced': replaced, 'items': nitems}),
                type='info')
        else:
            # Do everything you can find
            replaced = srutil.searchObjects(
                self.context,
                data['findWhat'],
                searchSubFolders=data.get('searchSubfolders', False),
                matchCase=data['matchCase'],
                replaceText=data['replaceWith'],
                onlySearchableText=data['onlySearchableText'],
                doReplace=True)
            IStatusMessage(self.request).addStatusMessage(
                _(u'Search text replaced in all ${items} instance(s).',
                  mapping={'items': replaced}),
                type='info')

    @action(_(u'Reset'),
            validator=None,
            name=u'Reset')
    def action_reset(self, action, data):
        """ Reset the form fields to their defaults. """
Exemple #12
0
class ISearchReplaceForm(Interface):
    """ Interface for Search and Replace form """

    findWhat = Text(
        title=_(u'Find What'),
        description=_(u'Enter the text to find.'),
        required=True)

    replaceWith = Text(
        title=_(u'Replace With'),
        description=_(u'Enter the text to replace the original text with.'),
        required=False)

    maxResults = Int(
        title=_(u'Maximum Number of Results'),
        description=_(
            u'Maximum number of results to show. '
            'Warning: this has no effect on how many found texts are '
            'replaced when you use the Replace button directly without '
            'using the Preview.'),
        default=None,
        required=False)

    searchSubfolders = Bool(
        title=_(u'Search Subfolders'),
        description=_(
            u'If checked, this will recursively search '
            'through any selected folders and their '
            'children, replacing at each level.'),
        default=True,
        required=True)

    matchCase = Bool(
        title=_(u'Match Case'),
        description=_(u'Check the box for a case sensitive search.'),
        default=False,
        required=True)

    onlySearchableText = Bool(
        title=_(u'Fast search'),
        description=_(
            u'Use the catalog to search, just like the search form does. '
            'This only finds keywords, not html tags. '
            'You might have some text fields that are not found this way, '
            'so if not checked, you may find more content, '
            'but it will be slower. '
            'Regardless of this setting, when at least one match is found, '
            'text in all text fields may be replaced.'),
        required=False,
        default=True,
    )
 def searchObjects(self, context, find, **kwargs):
     """ Search objects and optionally do a replace. """
     # Get search parameters
     cpath = context.getPhysicalPath()
     if 'searchSubFolders' in kwargs:
         ssf = kwargs['searchSubFolders']
     else:
         ssf = True
     if 'matchCase' in kwargs:
         mc = kwargs['matchCase']
     else:
         mc = False
     if 'replaceText' in kwargs:
         rtext = kwargs['replaceText']
     else:
         rtext = None
     if 'doReplace' in kwargs:
         replace = kwargs['doReplace']
     else:
         replace = False
     if 'searchItems' in kwargs:
         sitems = kwargs['searchItems']
     else:
         sitems = None
     # Get Regex matcher
     sflags = mc and searchflags or (searchflags | re.IGNORECASE)
     matcher = re.compile(find, sflags)
     # Get items to search
     query = {'query': '/'.join(cpath)}
     if context.isPrincipiaFolderish and not ssf:
         query['depth'] = 1
     container = aq_parent(context)
     if isDefaultPage(container, context) and ssf:
         query['query'] = '/'.join(container.getPhysicalPath())
     catalog = getToolByName(context, 'portal_catalog')
     brains = catalog(
         path=query,
         object_provides=searchinterfaces,
     )
     memship = getToolByName(context, 'portal_membership')
     checkPermission = memship.checkPermission
     # Match objects
     results = []
     replaced = 0
     outdated_catalog = False
     for b in brains:
         ipath = b.getPath()
         if not sitems or ipath in sitems:
             obj = b.getObject()
             if not ISearchReplaceable.providedBy(obj):
                 # Warn about this once.
                 if not outdated_catalog:
                     outdated_catalog = True
                     msg = _(
                         'Item found that does not implement '
                         'ISearchReplaceable. You should reindex the '
                         'object_provides index of the portal_catalog.')
                     logger.warn(msg)
                     request = getattr(context, 'REQUEST', None)
                     if request is not None:
                         IStatusMessage(request).addStatusMessage(
                             msg, type='warn')
                 continue
             # Does the user have the modify permission on this object?
             if not checkPermission(ModifyPortalContent, obj):
                 continue
             # If there is a filtered list of items, and it
             # is in the list, or if there is no filter
             # then process the item
             if replace and rtext:
                 # Do a replace
                 if sitems:
                     sitem = sitems[ipath]
                 else:
                     sitem = None
                 rep = self._replaceObject(matcher,
                                           obj,
                                           cpath,
                                           rtext,
                                           sitem)
                 replaced += rep
             elif not replace:
                 # Just find the matches and return info
                 result = self._searchObject(matcher, obj)
                 if result:
                     results += result
     if replace:
         return replaced
     else:
         return results