Beispiel #1
0
    def _get_due(self, value=None):
        if value is None:
            value = getattr(self.context, 'due', None)
            if not value:
                taskplanner = self._get_taskplanner(self.context)
                if taskplanner:
                    value = getattr(taskplanner, 'due', None)

        if not value:
            return

        _type = value.get('type')
        _value = value.get('value')

        if _type == 'date':
            return parse_datetime(_value)

        elif _type == 'computed':
            field4 = getattr(self.context, _value['field4'])

            if not field4:
                return

            field3 = self._get_value(_value['field3'], TIME_RELATIONS)[2]

            if safe_callable(field4):
                field4 = field4()
            if isinstance(field4, DateTime):
                field4 = pydt(field4)

            if field3 is None:
                return field4
            else:
                field2 = self._get_value(_value['field2'], TIME_UNITS)[2]
                field1 = int(_value['field1'])
                return field4 + field2(field3 * field1)

        elif _type == 'computed_dow':
            field4 = getattr(self.context, _value['field4'])

            if not field4:
                return

            field3 = self._get_value(_value['field3'], TIME_RELATIONS)[2]

            if safe_callable(field4):
                field4 = field4()
            if isinstance(field4, DateTime):
                field4 = pydt(field4)

            if field3 is None:
                return field4
            else:
                field2 = self._get_value(_value['field2'], DAYS_OF_WEEK)[2]
                field1 = int(_value['field1'])
                return field4 + field2(field3 * field1)
 def updateTranslatedPaths(obj, path=None):
     if (base_hasattr(obj, 'indexObject') and
         safe_callable(obj.indexObject) and
         base_hasattr(obj, 'getPhysicalPath') and
         safe_callable(obj.getPhysicalPath)):
         try:
             path = '/'.join(obj.getPhysicalPath())
             catalog._catalog.updateTanslatedPaths(obj, path)
             results.append('Updated %s' % path)
             transaction.commit()
         except:
             pass
Beispiel #3
0
def sortable_title(instance):
    """Uses the default Plone sortable_text index lower-case
    """
    title = plone_sortable_title(instance)
    if safe_callable(title):
        title = title()
    return title.lower()
Beispiel #4
0
    def toFieldValue(self, value):
        """Converts from widget value to field.

        :param value: Value inserted by datetime widget.
        :type value: string

        :returns: `datetime.datetime` object.
        :rtype: datetime
        """
        if not value:
            return self.field.missing_value
        tmp = value.split(' ')
        if not tmp[0]:
            return self.field.missing_value
        value = tmp[0].split('-')
        if len(tmp) == 2 and ':' in tmp[1]:
            value += tmp[1].split(':')
        else:
            value += ['00', '00']

        # TODO: respect the selected zone from the widget and just fall back
        # to default_zone
        default_zone = self.widget.default_timezone
        zone = default_zone(self.widget.context)\
            if safe_callable(default_zone) else default_zone
        ret = datetime(*map(int, value))
        if zone:
            tzinfo = pytz.timezone(zone)
            ret = tzinfo.localize(ret)
        return ret
Beispiel #5
0
    def _getNavQuery(self):
        context = self.context
        navtree_properties = self.navtree_properties

        customQuery = getattr(context, 'getCustomNavQuery', False)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        rootPath = getNavigationRoot(context)
        query['path'] = {'query': rootPath, 'depth': 1}

        blacklist = navtree_properties.getProperty('metaTypesNotToList', ())
        all_types = self.portal_catalog.uniqueValuesFor('portal_type')
        query['portal_type'] = [t for t in all_types if t not in blacklist]

        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        if navtree_properties.getProperty('enable_wf_state_filtering', False):
            query['review_state'] = navtree_properties.getProperty(
                                                    'wf_states_to_show', [])

        query['is_default_page'] = False

        if self.site_properties.getProperty('disable_nonfolderish_sections',
                                            False):
            query['is_folderish'] = True

        return query
Beispiel #6
0
    def get_pattern_options(self):
        portal = getToolByName(getSite(), 'portal_url').getPortalObject()
        ajax_url = portal.absolute_url() + '/@@json_recurrence'
        request = portal.REQUEST

        first_day = self.first_day
        first_day = first_day() if safe_callable(first_day) else first_day

        params = dict(
            ajaxContentType='application/x-www-form-urlencoded; charset=UTF-8',
            ajaxURL=ajax_url,
            firstDay=first_day,
            hasRepeatForeverButton=self.show_repeat_forever,
            lang=request.LANGUAGE,
            ributtonExtraClass='allowMultiSubmit',
            startField=self.startField,
            startFieldDay=self.startFieldDay,
            startFieldMonth=self.startFieldMonth,
            startFieldYear=self.startFieldYear,
        )
        return json.dumps({
            "locationization": translations(request),
            "language": request.LANGUAGE,
            "configuration": params
        })
Beispiel #7
0
 def process_value(self, value):
     """Process publication value
     """
     # UID -> ReportModel
     if self.is_uid(value):
         return self.to_report_model(value)
     # Content -> ReportModel
     elif api.is_object(value):
         return self.to_report_model(value)
     # String -> Unicode
     elif isinstance(value, basestring):
         return safe_unicode(value)
     # DateTime -> DateTime
     elif isinstance(value, DateTime):
         return value
     # Process list values
     elif isinstance(value, (LazyMap, list, tuple)):
         return map(self.process_value, value)
     # Process dict values
     elif isinstance(value, (dict)):
         return {k: self.process_value(v) for k, v in value.iteritems()}
     # Process function
     elif safe_callable(value):
         return self.process_value(value())
     # Always return the unprocessed value last
     return value
Beispiel #8
0
    def toFieldValue(self, value):
        """Converts from widget value to field.

        :param value: Value inserted by datetime widget.
        :type value: string

        :returns: `datetime.datetime` object.
        :rtype: datetime
        """
        if not value:
            return self.field.missing_value
        tmp = value.split(' ')
        if not tmp[0]:
            return self.field.missing_value
        value = tmp[0].split('-')
        if len(tmp) == 2 and ':' in tmp[1]:
            value += tmp[1].split(':')
        else:
            value += ['00', '00']

        # TODO: respect the selected zone from the widget and just fall back
        # to default_zone
        default_zone = self.widget.default_timezone
        zone = default_zone(self.widget.context)\
            if safe_callable(default_zone) else default_zone
        ret = datetime(*map(int, value))
        if zone:
            tzinfo = pytz.timezone(zone)
            ret = tzinfo.localize(ret)
        return ret
    def _getNavQuery(self):
        # check whether we only want actions
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(INavigationSchema,
                                                    prefix="plone",
                                                    check=False)
        customQuery = getattr(self.context, 'getCustomNavQuery', False)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        query['path'] = {'query': getNavigationRoot(self.context), 'depth': 1}
        query['portal_type'] = [t for t in navigation_settings.displayed_types]
        query['sort_on'] = navigation_settings.sort_tabs_on
        if navigation_settings.sort_tabs_reversed:
            query['sort_order'] = 'reverse'
        else:
            query['sort_order'] = 'ascending'

        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        query['is_default_page'] = False

        if not navigation_settings.nonfolderish_tabs:
            query['is_folderish'] = True

        return query
Beispiel #10
0
 def _get_compare_attr(obj, attr):
     val = getattr(obj, attr, None)
     if safe_callable(val):
         val = val()
     if isinstance(val, DateTime):
         val = pydt(val)
     return val
Beispiel #11
0
 def _get_compare_attr(obj, attr):
     val = getattr(obj, attr, None)
     if safe_callable(val):
         val = val()
     if isinstance(val, DateTime):
         val = pydt(val)
     return val
    def isExpired(content):
        """ Find out if the object is expired (copied from skin script) """

        expiry = None

        # NOTE: We also accept catalog brains as 'content' so that the
        # catalog-based folder_contents will work. It's a little
        # magic, but it works.

        # ExpirationDate should have an ISO date string, which we need to
        # convert to a DateTime

        # Try DC accessor first
        if base_hasattr(content, 'ExpirationDate'):
            expiry = content.ExpirationDate

        # Try the direct way
        if not expiry and base_hasattr(content, 'expires'):
            expiry = content.expires

        # See if we have a callable
        if safe_callable(expiry):
            expiry = expiry()

        # Convert to DateTime if necessary, ExpirationDate may return 'None'
        if expiry and expiry != 'None' and isinstance(expiry, basestring):
            expiry = DateTime(expiry)

        if isinstance(expiry, DateTime) and expiry.isPast():
            return 1
        return 0
Beispiel #13
0
    def indexObject(obj, path):

        if (base_hasattr(obj, 'indexObject') and
            safe_callable(obj.indexObject)):

            try:
                obj.indexObject()

                annotions = IAnnotations(obj)
                catalog = getToolByName(obj, 'portal_catalog', None)
                if ANNOTATION_KEY in annotions:
                    conversation = annotions[ANNOTATION_KEY]
                    conversation = conversation.__of__(obj)
                    for comment in conversation.getComments():
                        try:
                            comment = comment.__of__(conversation)
                            if catalog:
                                catalog.indexObject(comment)
                        except StopIteration: # pragma: no cover
                            pass

            except TypeError:
                # Catalogs have 'indexObject' as well, but they
                # take different args, and will fail
                pass
    def get_pattern_options(self):
        portal = getToolByName(getSite(), 'portal_url').getPortalObject()
        ajax_url = portal.absolute_url() + '/@@json_recurrence'
        request = portal.REQUEST

        first_day = self.first_day
        first_day = first_day() if safe_callable(first_day) else first_day

        params = dict(
            ajaxContentType='application/x-www-form-urlencoded; charset=UTF-8',
            ajaxURL=ajax_url,
            firstDay=first_day,
            hasRepeatForeverButton=self.show_repeat_forever,
            lang=request.LANGUAGE,
            ributtonExtraClass='allowMultiSubmit',
            startField=self.startField,
            startFieldDay=self.startFieldDay,
            startFieldMonth=self.startFieldMonth,
            startFieldYear=self.startFieldYear,
        )
        return json.dumps({
            "locationization": translations(request),
            "language": request.LANGUAGE,
            "configuration": params
        })
Beispiel #15
0
def sortable_title(obj):
    """Custom sortable_title indexer for RepositoryFolders.

    This implementation doesn't count space needed for zero padded numbers
    towards the maximum length. We need this for repofolders because otherwise
    for deeply nested folders the reference numbers alone eat up all
    the available space (40 characters).
    """
    title = getattr(obj, 'Title', None)
    if title is not None:
        if safe_callable(title):
            title = title()

        if isinstance(title, basestring):
            # Ignore case, normalize accents, strip spaces
            sortabletitle = mapUnicode(safe_unicode(title)).lower().strip()
            # Replace numbers with zero filled numbers
            sortabletitle = num_sort_regex.sub(zero_fill, sortabletitle)

            # Determine the length of the sortable title
            padded_numbers = re.findall(num_sort_regex, sortabletitle)
            max_length = MAX_SORTABLE_TITLE + sum([
                len(match) - len(match.lstrip('0'))
                for match in padded_numbers
            ])

            # Truncate to prevent bloat, take bits from start and end
            if len(sortabletitle) > max_length:
                start = sortabletitle[:(max_length - 13)]
                end = sortabletitle[-10:]
                sortabletitle = start + '...' + end
            return sortabletitle.encode('utf-8')
    return ''
Beispiel #16
0
 def process_value(self, value):
     """Process publication value
     """
     # UID -> SuperModel
     if api.is_uid(value):
         # Do not process "0" as the portal object
         # -> Side effect in specifications when the value is "0"
         if value == "0":
             return "0"
         return self.to_super_model(value)
     # Content -> SuperModel
     elif api.is_object(value):
         return self.to_super_model(value)
     # String -> Unicode
     elif isinstance(value, basestring):
         return safe_unicode(value).encode("utf-8")
     # DateTime -> DateTime
     elif isinstance(value, DateTime):
         return value
     # Process list values
     elif isinstance(value, (LazyMap, list, tuple)):
         return map(self.process_value, value)
     # Process dict values
     elif isinstance(value, (dict)):
         return {k: self.process_value(v) for k, v in value.iteritems()}
     # Process function
     elif safe_callable(value):
         return self.process_value(value())
     # Always return the unprocessed value last
     return value
Beispiel #17
0
    def stringify(self, value):
        """Convert value to string

        This method is used to generate a simple JSON representation of the
        object (without dereferencing objects etc.)
        """
        # SuperModel -> UID
        if ISuperModel.providedBy(value):
            return str(value)
        # DateTime -> ISO8601 format
        elif isinstance(value, (DateTime)):
            return value.ISO8601()
        # Image/Files -> filename
        elif safe_hasattr(value, "filename"):
            return value.filename
        # Dict -> convert_value_to_string
        elif isinstance(value, dict):
            return {k: self.stringify(v) for k, v in value.iteritems()}
        # List -> convert_value_to_string
        if isinstance(value, (list, tuple, LazyMap)):
            return map(self.stringify, value)
        # Callables
        elif safe_callable(value):
            return self.stringify(value())
        elif isinstance(value, unicode):
            value = value.encode("utf8")
        try:
            return str(value)
        except (AttributeError, TypeError, ValueError):
            logger.warn("Could not convert {} to string".format(repr(value)))
            return None
Beispiel #18
0
    def _getNavQuery(self):
        context = self.context
        navtree_properties = self.navtree_properties

        customQuery = getattr(context, 'getCustomNavQuery', False)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        rootPath = getNavigationRoot(context)
        query['path'] = {'query': rootPath, 'depth': 1}

        blacklist = navtree_properties.getProperty('metaTypesNotToList', ())
        all_types = self.portal_catalog.uniqueValuesFor('portal_type')
        query['portal_type'] = [t for t in all_types if t not in blacklist]

        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        if navtree_properties.getProperty('enable_wf_state_filtering', False):
            query['review_state'] = navtree_properties.getProperty(
                                                    'wf_states_to_show', [])

        query['is_default_page'] = False

        if self.site_properties.getProperty('disable_nonfolderish_sections',
                                            False):
            query['is_folderish'] = True

        return query
    def _getNavQuery(self):
                # check whether we only want actions
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(
            INavigationSchema,
            prefix="plone",
            check=False
        )
        customQuery = getattr(self.context, 'getCustomNavQuery', False)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        query['path'] = {
            'query': getNavigationRoot(self.context),
            'depth': 1
        }
        query['portal_type'] = [t for t in navigation_settings.displayed_types]
        query['sort_on'] = navigation_settings.sort_tabs_on
        if navigation_settings.sort_tabs_reversed:
            query['sort_order'] = 'reverse'
        else:
            query['sort_order'] = 'ascending'

        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        query['is_default_page'] = False

        if not navigation_settings.nonfolderish_tabs:
            query['is_folderish'] = True

        return query
Beispiel #20
0
def sortable_title(obj):
    """Custom sortable_title indexer for all content types.

    This is a copy from Products.CMFPlone.CatalogTool.sortable_title
    except that we overwrite MAX_SORTABLE_TITLE with SORTABLE_TITLE_LENGTH.
    We set set it to a high enough value to basically avoid ever cropping
    the title, even with number padding. This is to avoid sorting issues
    in content listings.
    """
    title = getattr(obj, 'Title', None)
    if title is not None:
        if safe_callable(title):
            title = title()

        if isinstance(title, basestring):
            # Ignore case, normalize accents, strip spaces
            sortabletitle = mapUnicode(safe_unicode(title)).lower().strip()
            # Replace numbers with zero filled numbers
            sortabletitle = num_sort_regex.sub(zero_fill, sortabletitle)
            # Truncate to prevent bloat, take bits from start and end
            if len(sortabletitle) > SORTABLE_TITLE_LENGTH:
                start = sortabletitle[:(SORTABLE_TITLE_LENGTH - 13)]
                end = sortabletitle[-10:]
                sortabletitle = start + u'...' + end
            return sortabletitle.encode('utf-8')
    return ''
Beispiel #21
0
    def tabular_fielddata(self, item, fieldname):
        """tabular_fielddata.

        :param item:
        :param fieldname:
        """
        value = getattr(item, fieldname, '')
        if safe_callable(value):
            value = value()
        if fieldname in [
                'CreationDate',
                'ModificationDate',
                'Date',
                'EffectiveDate',
                'ExpirationDate',
                'effective',
                'expires',
                'start',
                'end',
                'created',
                'modified',
                'last_comment_date']:
            value = self.context.toLocalizedTime(value, long_format=1)

        return {
            # 'title': _(fieldname, default=fieldname),
            'value': value
        }
Beispiel #22
0
    def _getNavQuery(self, rootPath=None):

        customQuery = getattr(self.context, 'getCustomNavQuery', False)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}
        if rootPath == None:
            rootPath = getMultiAdapter((self.context, self.request), name="plone_portal_state").navigation_root_path()
        query['path'] = {'query' : rootPath, 'depth' : 1}

        if self.sections_displayed_types:
            query['portal_type'] = self.sections_displayed_types
        else:
            query['portal_type'] = ['Folder', 'Collection', 'Topic', 'Collage', 'FormFolder']

        if self.sortAttribute is not None:
            query['sort_on'] = self.sortAttribute
            if self.sortOrder is not None:
                query['sort_order'] = self.sortOrder

        rootItem = self.context.restrictedTraverse(rootPath)

        if self.enable_wf_state_filtering and rootItem.portal_type not in ['MemberFolder']:
            query['review_state'] = self.sections_wf_states_to_show

        query['is_default_page'] = False
        
        if self.disable_nonfolderish_sections:
            query['is_folderish'] = True
        return query
Beispiel #23
0
    def __init__(self, context, data):
        self.context = context
        self.data = data

        portal_properties = getToolByName(context, "portal_properties")
        navtree_properties = getattr(portal_properties, "navtree_properties")

        # Acquire a custom nav query if available
        customQuery = getattr(context, "getCustomNavQuery", None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query
        root = get_root(context, data.root_path)
        if root is not None:
            rootPath = "/".join(root.getPhysicalPath())
        else:
            rootPath = getNavigationRoot(context)

        currentPath = "/".join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if currentPath != rootPath and not currentPath.startswith(rootPath +
                                                                  "/"):
            query["path"] = {"query": rootPath, "depth": 1}
        else:
            query["path"] = {"query": currentPath, "navtree": 1}

        topLevel = data.topLevel
        if topLevel and topLevel > 0:
            query["path"]["navtree_start"] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query["portal_type"] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty("sortAttribute", None)
        if sortAttribute is not None:
            query["sort_on"] = sortAttribute
            sortOrder = navtree_properties.getProperty("sortOrder", None)
            if sortOrder is not None:
                query["sort_order"] = sortOrder

        # Filter on workflow states, if enabled
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(INavigationSchema,
                                                    prefix="plone")
        if navigation_settings.filter_on_workflow:
            query["review_state"] = navigation_settings.workflow_states_to_show

        self.query = query
Beispiel #24
0
    def __init__(self, context, portlet):
        self.context = context
        self.portlet = portlet

        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query
        root = uuidToObject(portlet.root_uid)
        if root is not None:
            rootPath = '/'.join(root.getPhysicalPath())
        else:
            rootPath = getNavigationRoot(context)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if currentPath != rootPath and not currentPath.startswith(rootPath + '/'):
            query['path'] = {'query': rootPath, 'depth': 1}
        else:
            query['path'] = {'query': currentPath, 'navtree': 1}

        topLevel = portlet.topLevel
        if topLevel and topLevel > 0:
            query['path']['navtree_start'] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(
            INavigationSchema,
            prefix="plone"
        )
        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        self.query = query
Beispiel #25
0
 def is_indexable(self, obj):
     """Checks if the object can be indexed
     """
     if not (base_hasattr(obj, "reindexObject")):
         return False
     if not (safe_callable(obj.reindexObject)):
         return False
     return True
def get_id(item):
    if not item:
        return None
    getId = getattr(item, 'getId')
    if not utils.safe_callable(getId):
        # Looks like a brain
        return getId
    return getId()
def get_id(item):
    if not item:
        return ''
    getId = getattr(item, 'getId')
    if not utils.safe_callable(getId):
        # Looks like a brain
        return getId
    return getId()
Beispiel #28
0
 def _indexObject(obj):
     if (base_hasattr(obj, 'getObject') and
         safe_callable(obj.getObject)):
         # Wake up any brains
         obj = obj.getObject()
     if (base_hasattr(obj, 'indexObject') and
         safe_callable(obj.indexObject)):
         try:
             obj.indexObject()
         except TypeError:
             # Catalogs have 'indexObject' as well, but they
             # take different args, and will fail
             pass
         except:
             # Log indexing exceptions but continue
             log_exc('Could not reindex %s'%(
                 '/'.join(obj.getPhysicalPath())))
    def __init__(self, context, portlet):
        self.context = context
        self.portlet = portlet
        
        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')
        
        portal_url = getToolByName(context, 'portal_url')
        
        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query

        rootPath = getNavigationRoot(context, relativeRoot=portlet.root)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if not currentPath.startswith(rootPath):
            query['path'] = {'query' : rootPath, 'depth' : 1}
        else:
            query['path'] = {'query' : currentPath, 'navtree' : 1}

        topLevel = portlet.topLevel or navtree_properties.getProperty('topLevel', 0)
        if topLevel and topLevel > 0:
             query['path']['navtree_start'] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        if navtree_properties.getProperty('enable_wf_state_filtering', False):
            query['review_state'] = navtree_properties.getProperty('wf_states_to_show', ())

        ############# Added by expanding navigation
        query['path']['navtree']=''
        query['path']['query']=''
        ############# End added

        self.query = query
Beispiel #30
0
    def __init__(self, context, portlet):
        self.context = context
        self.portlet = portlet

        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query
        root = uuidToObject(portlet.root_uid)
        if root is not None:
            rootPath = '/'.join(root.getPhysicalPath())
        else:
            rootPath = getNavigationRoot(context)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if currentPath != rootPath and not currentPath.startswith(rootPath +
                                                                  '/'):
            query['path'] = {'query': rootPath, 'depth': 1}
        else:
            query['path'] = {'query': currentPath, 'navtree': 1}

        topLevel = portlet.topLevel
        if topLevel and topLevel > 0:
            query['path']['navtree_start'] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(INavigationSchema,
                                                    prefix="plone")
        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        self.query = query
Beispiel #31
0
 def getMethodAliases(self, typeInfo):
     """Given an FTI, return the dict of method aliases defined on that
     FTI. If there are no method aliases (i.e. this FTI doesn't support it),
     return None"""
     getMethodAliases = getattr(typeInfo, "getMethodAliases", None)
     if getMethodAliases is not None and utils.safe_callable(getMethodAliases):
         return getMethodAliases()
     else:
         return None
Beispiel #32
0
 def indexObject(obj, path):
     if (base_hasattr(obj, 'indexObject') and
         safe_callable(obj.indexObject)):
         try:
             obj.indexObject()
         except TypeError:
             # Catalogs have 'indexObject' as well, but they
             # take different args, and will fail
             pass
Beispiel #33
0
    def __init__(self, context, portlet):
        self.context = context
        self.portlet = portlet

        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')

        portal_url = getToolByName(context, 'portal_url')

        portal_languages = getToolByName(context, 'portal_languages')

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}
        #import pdb;pdb.set_trace()
        # Construct the path query
        preferred_path = "/%s" % portal_languages.getPreferredLanguage()

        rootPathX = getNavigationRoot(context, relativeRoot=portlet.root)
        rootPathY = getNavigationRoot(context, relativeRoot=preferred_path)

        rootPath = portal_url.getPortalPath()+preferred_path

        print "X: portlet.root based. rootPath: %s, portlet.root: %s" %(rootPathX, portlet.root)
        print "Y: preferred_path based. rootPath: %s, preferred_path: %s" %(rootPathY, preferred_path)
        print "Current: rootPath+preferred_path: %s %s" %(rootPath, preferred_path)

        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        query['path'] = {'query' : rootPath, 'navtree' : 1, 'navtree_start': 1}

        topLevel = portlet.topLevel or navtree_properties.getProperty('topLevel', 0)
        topLevel = 0

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        if navtree_properties.getProperty('enable_wf_state_filtering', False):
            query['review_state'] = navtree_properties.getProperty('wf_states_to_show', ())

        self.query = query
 def indexObject(obj, path):
     if (base_hasattr(obj, 'indexObject')
             and safe_callable(obj.indexObject)):
         try:
             obj.indexObject()
         except TypeError:
             # Catalogs have 'indexObject' as well, but they
             # take different args, and will fail
             pass
    def __init__(self, context, portlet):
        self.context = context
        self.portlet = portlet

        portal_url = getToolByName(context, 'portal_url')
        portal = portal_url.getPortalObject()
        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')
        pm = getToolByName(portal,'portal_membership')
        user = pm.getAuthenticatedMember()
        
        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query
        if hasattr(portlet, 'root'):
            root = portlet.root
        else:
            root = uuidToObject(portlet.root_uid)
        rootPath = getNavigationRoot(context, relativeRoot=root)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        query['path'] = {'query' : rootPath, 'depth' : 2}

        topLevel = portlet.topLevel or navtree_properties.getProperty('topLevel', 0)
        if topLevel and topLevel > 0:
             query['path']['navtree_start'] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        if not user or not user.has_permission('List folder contents', self.context):
            if navtree_properties.getProperty('enable_wf_state_filtering', False):
                query['review_state'] = navtree_properties.getProperty('wf_states_to_show', ())

        self.query = query
Beispiel #36
0
def _get_compare_attr(obj, attr):
    """Return an compare attribute, supporting AT, DX and IEventAccessor
    objects.
    """
    val = getattr(obj, attr, None)
    if safe_callable(val):
        val = val()
    if isinstance(val, DateTime):
        val = pydt(val)
    return val
Beispiel #37
0
def _get_compare_attr(obj, attr):
    """Return an compare attribute, supporting AT, DX and IEventAccessor
    objects.
    """
    val = getattr(obj, attr, None)
    if safe_callable(val):
        val = val()
    if isinstance(val, DateTime):
        val = pydt(val)
    return val
Beispiel #38
0
 def getMethodAliases(self, typeInfo):
     # Given an FTI, return the dict of method aliases defined on that
     # FTI. If there are no method aliases (i.e. this FTI doesn't support
     # it), return None.
     getMethodAliases = getattr(typeInfo, 'getMethodAliases', None)
     if getMethodAliases is not None \
             and utils.safe_callable(getMethodAliases):
         return getMethodAliases()
     else:
         return None
 def getEntry(self, object):
     attrs = re.findall('%\([^\)]+\)', self.contents)
     map = {}
     for attr in attrs:
         attr = attr[2:-1]
         if map.has_key(attr):
             continue
         value = getattr(object, attr, '')
         modifier = getattr(self, attr, None)
         if modifier and safe_callable(modifier):
             value = modifier(object, value)
         elif safe_callable(value):
             value = value()
         if value and not attr in self.noescape:
             value = vformat(value)
         map[attr] = safe_unicode(value)
     for required in self.required:
         if not map[required]:
             return ''
     return self.template % {'contents': self.contents % map}
Beispiel #40
0
 def getEntry(self, object):
     attrs = re.findall('%\([^\)]+\)', self.contents)
     map = {}
     for attr in attrs:
         attr = attr[2:-1]
         if map.has_key(attr):
             continue
         value = getattr(object, attr, '')
         modifier = getattr(self, attr, None)
         if modifier and safe_callable(modifier):
             value = modifier(object, value)
         elif safe_callable(value):
             value = value()
         if value and not attr in self.noescape:
             value = vformat(value)
         map[attr] = safe_unicode(value)
     for required in self.required:
         if not map[required]:
             return ''
     return self.template % {'contents': self.contents % map}
def get_data(content, security=False, domain=None):
    """Return data to index in ES.
    """
    uid = get_uid(content)
    if not uid:
        return None, None
    title = content.Title()
    try:
        # wrap content, so the SearchableText will be
        # delegated to IIndexer adapters as appropriate.
        # This will e.g. take care of PDF file indexing.
        cat = getToolByName(content, 'portal_catalog')
        wrapper = IndexableObjectWrapper(content, cat)
        text = getattr(wrapper, 'SearchableText', None)
        if safe_callable(text):
            text = text()

    except:
        text = title
    url = content.absolute_url()
    if domain:
        parts = urlparse.urlparse(url)
        url = urlparse.urlunparse((parts[0], domain) + parts[2:])

    data = {'title': title,
            'metaType': content.portal_type,
            'sortableTitle': sortable_string(title),
            'description': content.Description(),
            'subject': content.Subject(),
            'contributors': content.Contributors(),
            'url': url,
            'author': content.Creator(),
            'content': text}

    if security:
        data['authorizedUsers'] = get_security(content)

    if hasattr(aq_base(content), 'pub_date_year'):
        data['publishedYear'] = getattr(content, 'pub_date_year')

    created = content.created()
    if created is not (None, 'None'):
        data['created'] = created.strftime('%Y-%m-%dT%H:%M:%S')

    modified = content.modified()
    if modified is not (None, 'None'):
        data['modified'] = modified.strftime('%Y-%m-%dT%H:%M:%S')

    if (not security or 'Anonymous' in data['authorizedUsers']) and \
            IContentish.providedBy(content):
        data['suggest'] = ISuggester(content).terms()

    return uid, data
Beispiel #42
0
def sortable_sortkey_title(instance):
    """Returns a sortable title as a mxin of sortkey + lowercase sortable_title
    """
    title = sortable_title(instance)
    if safe_callable(title):
        title = title()

    sort_key = instance.getSortKey()
    if sort_key is None:
        sort_key = 999999

    return "{:010.3f}{}".format(sort_key, title)
Beispiel #43
0
def sortable_title(obj):
    title = getattr(obj, 'Title', None)
    if title is not None:
        if safe_callable(title):
            title = title()

        if isinstance(title, basestring):
            sortabletitle = safe_unicode(title).lower().strip()
            sortabletitle = num_sort_regex.sub(zero_fill, sortabletitle)
            sortabletitle = sortabletitle[:70].encode('utf-8')
            return locale.strxfrm(sortabletitle)

    return ''
Beispiel #44
0
def _pretty_title_or_id(context, obj, empty_value=_marker):
    """Return the best possible title or id of an item, regardless
       of whether obj is a catalog brain or an object, but returning an
       empty title marker if the id is not set (i.e. it's auto-generated).
    """
    # if safe_hasattr(obj, 'aq_explicit'):
    #    obj = obj.aq_explicit
    #title = getattr(obj, 'Title', None)
    title = None
    if base_hasattr(obj, 'Title'):
        title = getattr(obj, 'Title', None)
    if safe_callable(title):
        title = title()
    if title:
        return title
    item_id = getattr(obj, 'getId', None)
    if safe_callable(item_id):
        item_id = item_id()
    if item_id and not isIDAutoGenerated(context, item_id):
        return item_id
    if empty_value is _marker:
        empty_value = getEmptyTitle(context)
    return empty_value
Beispiel #45
0
def _pretty_title_or_id(context, obj, empty_value=_marker):
    """Return the best possible title or id of an item, regardless
       of whether obj is a catalog brain or an object, but returning an
       empty title marker if the id is not set (i.e. it's auto-generated).
    """
    # if safe_hasattr(obj, 'aq_explicit'):
    #    obj = obj.aq_explicit
    #title = getattr(obj, 'Title', None)
    title = None
    if base_hasattr(obj, 'Title'):
        title = getattr(obj, 'Title', None)
    if safe_callable(title):
        title = title()
    if title:
        return title
    item_id = getattr(obj, 'getId', None)
    if safe_callable(item_id):
        item_id = item_id()
    if item_id and not isIDAutoGenerated(context, item_id):
        return item_id
    if empty_value is _marker:
        empty_value = getEmptyTitle(context)
    return empty_value
Beispiel #46
0
 def indexObject(obj, path):	    
     if (base_hasattr(obj, 'indexObject') and
         safe_callable(obj.indexObject)):
         try:
             obj.indexObject()
             pdtool = obj.portal_discussion
             if pdtool.isDiscussionAllowedFor(obj):                        
                 tb = pdtool.getDiscussionFor(obj)
                 for ob in tb.getReplies():
                         ob.indexObject()
         except TypeError:
             # Catalogs have 'indexObject' as well, but they
             # take different args, and will fail
             pass
    def getQuery(self, context):
        user = self.portal_state.member()

        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query

        rootPath = self.navigationTreeRootPath()
        currentPath = '/'.join(context.getPhysicalPath())
        query['is_default_page'] = False
        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if currentPath!=rootPath and not currentPath.startswith(rootPath+'/'):
            query['path'] = {'query' : rootPath, 'depth' : 1}
        else:
            query['path'] = {'query' : currentPath, 'navtree' : 1}

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        ploneUtils = getToolByName(self.context, 'plone_utils')
        friendlyTypes = ploneUtils.getUserFriendlyTypes()
        if 'MemberDataContainer' in friendlyTypes:
            friendlyTypes.remove('MemberDataContainer')
        query['portal_type'] = friendlyTypes

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        if not user or not user.has_permission('List folder contents', self.context):
            if navtree_properties.getProperty('enable_wf_state_filtering', False):
                query['review_state'] = navtree_properties.getProperty('wf_states_to_show', ())
        return query
Beispiel #48
0
    def __init__(self, context):
        portal_properties = getToolByName(context, 'portal_properties')
        navtree_properties = getattr(portal_properties, 'navtree_properties')

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query

        rootPath = getNavigationRoot(context)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if not currentPath.startswith(rootPath):
            query['path'] = {'query': rootPath, 'depth': 1}
        else:
            query['path'] = {'query': currentPath, 'navtree': 1}

        topLevel = navtree_properties.getProperty('topLevel', 0)
        if topLevel and topLevel > 0:
            query['path']['navtree_start'] = topLevel + 1

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            sortOrder = navtree_properties.getProperty('sortOrder', None)
            if sortOrder is not None:
                query['sort_order'] = sortOrder

        # Filter on workflow states, if enabled
        if navtree_properties.getProperty('enable_wf_state_filtering', False):
            query['review_state'] = \
                navtree_properties.getProperty('wf_states_to_show', ())

        self.query = query
    def __init__(self, context):
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(INavigationSchema,
                                                    prefix="plone")

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query

        rootPath = getNavigationRoot(context)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if not currentPath.startswith(rootPath):
            query['path'] = {'query': rootPath, 'depth': 1}
        else:
            query['path'] = {'query': currentPath, 'navtree': 1}

        query['path']['navtree_start'] = 0

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navigation_settings.sort_tabs_on
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            if navigation_settings.sort_tabs_reversed:
                query['sort_order'] = 'desc'
            else:
                query['sort_order'] = 'asc'

        # Filter on workflow states, if enabled
        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        self.query = query
    def __init__(self, context):
        registry = getUtility(IRegistry)
        navigation_settings = registry.forInterface(INavigationSchema,
                                                    prefix="plone")

        # Acquire a custom nav query if available
        customQuery = getattr(context, 'getCustomNavQuery', None)
        if customQuery is not None and utils.safe_callable(customQuery):
            query = customQuery()
        else:
            query = {}

        # Construct the path query

        rootPath = getNavigationRoot(context)
        currentPath = '/'.join(context.getPhysicalPath())

        # If we are above the navigation root, a navtree query would return
        # nothing (since we explicitly start from the root always). Hence,
        # use a regular depth-1 query in this case.

        if not currentPath.startswith(rootPath):
            query['path'] = {'query': rootPath, 'depth': 1}
        else:
            query['path'] = {'query': currentPath, 'navtree': 1}

        query['path']['navtree_start'] = 0

        # XXX: It'd make sense to use 'depth' for bottomLevel, but it doesn't
        # seem to work with EPI.

        # Only list the applicable types
        query['portal_type'] = utils.typesToList(context)

        # Apply the desired sort
        sortAttribute = navigation_settings.sort_tabs_on
        if sortAttribute is not None:
            query['sort_on'] = sortAttribute
            if navigation_settings.sort_tabs_reversed:
                query['sort_order'] = 'desc'
            else:
                query['sort_order'] = 'asc'

        # Filter on workflow states, if enabled
        if navigation_settings.filter_on_workflow:
            query['review_state'] = navigation_settings.workflow_states_to_show

        self.query = query
Beispiel #51
0
    def notifications(self):
        dates = []
        rules = None

        # if assignee is asking for notifications look first if there are
        # customezed ones
        current = api.user.get_current().getId()
        annotations = self._setup_annotations()
        assignee = getattr(self.context, 'assignee', None)
        if assignee and current in assignee and \
                current in annotations[TASK_NOTIFICATIONS_KEY]:
            rules = annotations[TASK_NOTIFICATIONS_KEY][current]

        # in all other cases just return notifications
        else:
            rules = getattr(self.context, 'notifications', None)
            if not rules:
                taskplanner = self._get_taskplanner(self.context)
                if taskplanner:
                    rules = getattr(taskplanner, 'notifications', None)

        if rules:
            for rule in rules:
                if rule['field4'] == 'due':
                    field4 = self._get_due(
                        getattr(self.context, rule['field4']))
                else:
                    field4 = getattr(self.context, rule['field4'])

                if not field4:
                    continue

                field3 = self._get_value(rule['field3'], TIME_RELATIONS)[2]

                if safe_callable(field4):
                    field4 = field4()
                if isinstance(field4, DateTime):
                    field4 = pydt(field4)

                if field3 is None:
                    dates.append(field4)
                else:
                    field2 = self._get_value(rule['field2'], TIME_UNITS)[2]
                    field1 = int(rule['field1'])
                    dates.append(field4 + field2(field3 * field1))

        return dates
Beispiel #52
0
def sortable_id(obj):
    """put any zeros before the id
    so its possible to sort the id correctly
    """

    _id = getattr(obj, 'getId', None)
    if _id is not None:
        if safe_callable(_id):
            _id = _id()
        if isinstance(_id, basestring):
            value = _id.lower().strip()
            # Replace numbers with zero filled numbers
            value = num_sort_regex.sub(zero_fill, value)
            # Truncate to prevent bloat
            value = safe_unicode(value)[:40].encode('utf-8')
            return value
    return ''
 def __call__(self, **kwargs):
     title = getattr(self.obj, 'Title', None)
     if title is not None:
         if safe_callable(title):
             if kwargs.has_key('lang'):
                 try: title = title(lang=kwargs['lang'])
                 except: title = title()
             else:
                 title = title()
         if isinstance(title, basestring):
             sortabletitle = title.lower().strip()
             # Replace numbers with zero filled numbers
             sortabletitle = num_sort_regex.sub(zero_fill, sortabletitle)
             # Truncate to prevent bloat
             sortabletitle = safe_unicode(sortabletitle)[:30].encode('utf-8')
             return sortabletitle
     return ''
Beispiel #54
0
    def render(self, content, field_id):
        """Dexterity type rendering of field values"""
        # https://github.com/plone/plone.app.contenttypes/blob/master/plone/app/contenttypes/browser/folder.py
        renderer = self.render_methods_dx.get(field_id, None)
        if renderer is not None:
            return renderer(content, field_id)
        value = getattr(content, field_id, '')
        # catch relation fields
        target = getattr(value, 'to_object', None)
        if target is not None:
            title = target.Title()
            url = target.absolute_url()
            return "<a href='%s'>%s</a>" % (url, title)
        if safe_callable(value):
            value = value()

        return value
Beispiel #55
0
 def indexObject(obj, path):
     if (base_hasattr(obj, 'reindexObject')
             and safe_callable(obj.reindexObject)):
         try:
             self.reindexObject(obj, idxs=idxs)
             # index conversions from plone.app.discussion
             annotions = IAnnotations(obj)
             if DISCUSSION_ANNOTATION_KEY in annotions:
                 conversation = annotions[DISCUSSION_ANNOTATION_KEY]
                 conversation = conversation.__of__(obj)
                 for comment in conversation.getComments():
                     try:
                         self.indexObject(comment, idxs=idxs)
                     except StopIteration:  # pragma: no cover
                         pass
         except TypeError:
             # Catalogs have 'indexObject' as well, but they
             # take different args, and will fail
             pass