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
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))
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
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)
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
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
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
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
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
def get_items(self, resource, context): links = resource.get_links() query = OrQuery(*[PhraseQuery('abspath', link) for link in links]) return context.database.search(query)
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
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