示例#1
0
    def get_search_query(self, user, permission, class_id=None):
        # Special case: admins can see everything
        user_groups, is_admin = self._get_user_groups(user)
        if is_admin:
            return AllQuery()

        # 1. Back-office access rules
        rules_query = OrQuery()
        for rule in self.get_resources():
            if rule.get_value('permission') != permission:
                continue

            if rule.get_value('group') not in user_groups:
                continue

            if permission == 'add':
                r_format = rule.get_value('search_format')
                if class_id and r_format and class_id != r_format:
                    continue

            rules_query.append(rule.get_search_query())

        # Case: anonymous
        if not user:
            return AndQuery(rules_query, PhraseQuery('share', 'everybody'))

        # Case: authenticated
        share_query = OrQuery(*[PhraseQuery('share', x) for x in user_groups])
        share_query.append(PhraseQuery('share', str(user.abspath)))
        query = AndQuery(rules_query, share_query)

        if permission != 'share':
            return OrQuery(PhraseQuery('owner', str(user.abspath)), query)

        return query
示例#2
0
 def test_OrQuery_with_AllQuery(self):
     query1 = OrQuery(PhraseQuery('data', u'lion'), AllQuery())
     results1 = self.database.search(query1)
     # Must be equal to AllQuery
     query2 = AllQuery()
     results2 = self.database.search(query2)
     self.assertEqual(len(results1), len(results2))
示例#3
0
    def get_items_query(self, resource, context):
        # Search in subtree
        query = get_base_path_query(resource.abspath, max_depth=self.depth)

        # Base classes
        base_classes = self.base_classes
        if base_classes is not None:
            base_classes_query = OrQuery(
                *[PhraseQuery('base_classes', x) for x in base_classes])
            query = AndQuery(query, base_classes_query)
        # Ok
        return query
示例#4
0
    def get_items(self, resource, context):
        # Build the Query
        search_query = PhraseQuery('format', 'user')
        search_term = context.query['search_term'].strip()
        if search_term:
            search_query = AndQuery(search_query)
            or_query = OrQuery(TextQuery('lastname', search_term),
                               TextQuery('firstname', search_term),
                               StartQuery('email', search_term),
                               StartQuery('email_domain', search_term))
            search_query.append(or_query)

        # Ok
        return context.search(search_query)
示例#5
0
 def get_search_query(self, resource, context):
     query = AndQuery()
     form = context.query
     for key, datatype in self.search_schema.items():
         value = form[key]
         if value is None or value == '':
             continue
         # Special case: search on text, title and name AS AndQuery
         if key == 'text':
             text_query = []
             value = value.split(' ')
             for v in value:
                 t_query = OrQuery(TextQuery('title', v),
                                   TextQuery('text', v),
                                   PhraseQuery('name', v))
                 text_query.append(t_query)
             if len(text_query) == 1:
                 text_query = text_query[0]
             else:
                 text_query = AndQuery(*text_query)
             query.append(text_query)
         # Special case: type
         elif key == 'format':
             squery = [PhraseQuery('format', x) for x in value.split(',')]
             squery = squery[0] if len(squery) == 1 else OrQuery(*squery)
             query.append(squery)
         # Multiple
         elif datatype.multiple is True:
             query.append(OrQuery(*[PhraseQuery(key, x) for x in value]))
         # Singleton
         else:
             if value is False:
                 # FIXME No value means False in xapian
                 query.append(NotQuery(PhraseQuery(key, True)))
             else:
                 query.append(PhraseQuery(key, value))
     return query
示例#6
0
    def get_items_query(self, resource, context):
        # Search in subtree
        query = get_base_path_query(resource.abspath, max_depth=self.depth)

        # Base classes
        base_classes = self.base_classes
        if base_classes is not None:
            base_classes_query = OrQuery(
                *[PhraseQuery('base_classes', x) for x in base_classes])
            query = AndQuery(query, base_classes_query)

        # Exclude non-content
        if self.search_content_only(resource, context) is True:
            query = AndQuery(query, PhraseQuery('is_content', True))

        return query
示例#7
0
    def get_items(self, resource, context):
        # Make the base search
        items = super(Config_Orphans, self).get_items(context.root, context)

        # Show only the orphan resources
        items = [ x for x in items.get_documents()
                  if len(context.database.search(links=x.abspath)) == 0 ]

        # Transform back the items found in a SearchResults object.
        # FIXME This is required by 'get_item_value', we should change that,
        # for better performance.
        args = [ PhraseQuery('abspath', x.abspath) for x in items ]
        query = OrQuery(*args)
        items = context.search(query)

        # Ok
        return items
示例#8
0
def get_base_path_query(path, min_depth=1, max_depth=None):
    """Builds a query that will return all the objects within the given
    absolute path, like it is returned by 'resource.abspath'.

    The minimum and maximum depth parameters are relative to the given path:

    - If the minimum depth is zero it means include the container
    - If the maximum depth is None it means unlimited.
    """
    # Preprocess input data
    if type(path) is not str:
        path = str(path)

    if max_depth is not None and max_depth < min_depth:
        err = 'maximum depth (%d) smaller than minimum depth (%d)'
        raise ValueError, err % (max_depth, min_depth)

    # Special case: everything
    if path == '/' and min_depth == 0 and max_depth is None:
        return AllQuery()

    # Special case: just the given path
    if min_depth == 0 and max_depth == 0:
        return PhraseQuery('abspath', path)

    # Standard case
    query = PhraseQuery('parent_paths', path)
    if min_depth > 1 or max_depth is not None:
        path_depth = path.rstrip('/').count('/')
        a = path_depth + min_depth
        b = path_depth + max_depth if max_depth is not None else None
        query = AndQuery(query, RangeQuery('abspath_depth', a, b))

    if min_depth == 0:
        return OrQuery(query, PhraseQuery('abspath', path))

    return query
示例#9
0
    def get_search_query(self, user, permission, class_id=None):
        # Special case: admins can see everything
        user_groups, is_admin = self._get_user_groups(user)
        if is_admin:
            return AllQuery()

        # 1. Back-office access rules
        rules_query = OrQuery()
        for rule in self.get_resources():
            if rule.get_value('permission') != permission:
                continue

            if rule.get_value('group') not in user_groups:
                continue

            if permission == 'add':
                r_format = rule.get_value('search_format')
                if class_id and r_format and class_id != r_format:
                    continue

            rules_query.append(rule.get_search_query())

        # Case: anonymous
        if not user:
            return AndQuery(rules_query, PhraseQuery('share', 'everybody'))

        # Case: authenticated
        share_query = OrQuery(*[ PhraseQuery('share', x)
                                 for x in user_groups ])
        share_query.append(PhraseQuery('share', str(user.abspath)))
        query = AndQuery(rules_query, share_query)

        if permission != 'share':
            return OrQuery(PhraseQuery('owner', str(user.abspath)), query)

        return query
示例#10
0
 def get_items(self, resource, context):
     links = resource.get_links()
     query = OrQuery(*[PhraseQuery('abspath', link) for link in links])
     return context.database.search(query)
示例#11
0
    def _before_commit(self):
        root = self.get_resource('/')
        context = get_context()
        if context.database != self:
            raise ValueError('The contextual database is not coherent')

        # Update resources
        for path in deepcopy(self.resources_new2old):
            resource = root.get_resource(path)
            resource.update_resource(context)

        # 1. Update links when resources moved
        # XXX With this code '_on_move_resource' is called for new resources,
        # should this be done?
        old2new = [ (s, t) for s, t in self.resources_old2new.items()
                    if t and s != t ]
        old2new.sort(key=lambda x: x[1])     # Sort by target
        for source, target in old2new:
            target = Path(target)
            resource = root.get_resource(target)
            resource._on_move_resource(source)

        # 2. Find out resources to re-index because they depend on another
        # resource that changed
        to_reindex = set()
        aux = set()
        aux2 = set(self.resources_old2new.keys())
        while len(aux) != len(aux2):
            aux = set(aux2)
            # XXX we regroup items by 200 because Xapian is slow
            # when there's too much items in OrQuery
            l_aux = list(aux)
            for sub_aux in [l_aux[n:n+200] for n in range(0, len(l_aux), 200)]:
                query = [ PhraseQuery('onchange_reindex', x) for x in sub_aux ]
                query = OrQuery(*query)
                search = self.search(query)
                for brain in search.get_documents():
                    path = brain.abspath
                    aux2.add(path)
                    to_reindex.add(path)

        # 3. Documents to unindex (the update_links methods calls
        # 'change_resource' which may modify the resources_old2new dictionary)
        docs_to_unindex = self.resources_old2new.keys()
        self.resources_old2new.clear()

        # 4. Update mtime/last_author
        user = context.user
        userid = user.name if user else None
        for path in self.resources_new2old:
            if context.set_mtime:
                resource = root.get_resource(path)
                resource.metadata.set_property('mtime', context.timestamp)
                resource.metadata.set_property('last_author', userid)
        # Remove from to_reindex if resource has been deleted
        to_reindex = to_reindex - set(docs_to_unindex)
        # 5. Index
        docs_to_index = self.resources_new2old.keys()
        docs_to_index = set(docs_to_index) | to_reindex
        docs_to_unindex = list(set(docs_to_unindex) - docs_to_index)
        docs_to_index = list(docs_to_index)
        aux = []
        for path in docs_to_index:
            resource = root.get_resource(path, soft=True)
            if resource:
                values = resource.get_catalog_values()
                aux.append((resource, values))
        docs_to_index = aux
        self.resources_new2old.clear()

        # 6. Find out commit author & message
        if user:
            user_email = user.get_value('email')
            git_author = (userid, user_email or 'nobody')
        else:
            git_author = ('nobody', 'nobody')

        git_msg = getattr(context, 'git_message', None)
        if not git_msg:
            if context.method and context.uri:
                git_msg = "%s %s" % (context.method, context.uri)

                action = getattr(context, 'form_action', None)
                if action:
                    git_msg += " action: %s" % action
        else:
            git_msg = git_msg.encode('utf-8')

        # Ok
        git_date = context.fix_tzinfo(context.timestamp)
        return git_author, git_date, git_msg, docs_to_index, docs_to_unindex
示例#12
0
    def _before_commit(self):
        context = get_context()
        root = context.root

        # 1. Update links when resources moved
        # XXX With this code '_on_move_resource' is called for new resources,
        # should this be done?
        old2new = [(s, t) for s, t in self.resources_old2new.items()
                   if t and s != t]
        old2new.sort(key=lambda x: x[1])  # Sort by target
        for source, target in old2new:
            target = Path(target)
            resource = root.get_resource(target)
            resource._on_move_resource(source)

        # 2. Find out resources to re-index because they depend on another
        # resource that changed
        to_reindex = set()
        aux = set()
        aux2 = set(self.resources_old2new.keys())
        while len(aux) != len(aux2):
            aux = set(aux2)
            query = [PhraseQuery('onchange_reindex', x) for x in aux]
            query = OrQuery(*query)
            search = self.search(query)
            for brain in search.get_documents():
                path = brain.abspath
                aux2.add(path)
                to_reindex.add(path)

        # 3. Documents to unindex (the update_links methods calls
        # 'change_resource' which may modify the resources_old2new dictionary)
        docs_to_unindex = self.resources_old2new.keys()
        docs_to_unindex = list(set(docs_to_unindex) | to_reindex)
        self.resources_old2new.clear()

        # 4. Update mtime/last_author
        user = context.user
        userid = user.name if user else None
        if context.set_mtime:
            for path in self.resources_new2old:
                resource = root.get_resource(path)
                resource.metadata.set_property('mtime', context.timestamp)
                resource.metadata.set_property('last_author', userid)

        # 5. Index
        docs_to_index = self.resources_new2old.keys()
        docs_to_index = list(set(docs_to_index) | to_reindex)
        aux = []
        for path in docs_to_index:
            resource = root.get_resource(path, soft=True)
            if resource:
                values = resource.get_catalog_values()
                aux.append((resource, values))
        docs_to_index = aux
        self.resources_new2old.clear()

        # 6. Find out commit author & message
        if user:
            git_author = (userid, user.get_value('email'))
        else:
            git_author = ('nobody', 'nobody')

        git_msg = getattr(context, 'git_message', None)
        if not git_msg:
            git_msg = "%s %s" % (context.method, context.uri)

            action = getattr(context, 'form_action', None)
            if action:
                git_msg += " action: %s" % action
        else:
            git_msg = git_msg.encode('utf-8')

        # Ok
        git_date = context.fix_tzinfo(context.timestamp)
        return git_author, git_date, git_msg, docs_to_index, docs_to_unindex