def get_record_acls(clz, record: Record) -> Iterable['ACL']: """ Returns a list of ACL objects applicable for the given record. :param record: Invenio record :return: """ # run percolate query on the index record's index query = clz._get_percolate_query(record) if logger.isEnabledFor(logging.DEBUG) <= logging.DEBUG: logger.debug('get_material_acls: query %s', json.dumps(query, indent=4, ensure_ascii=False)) index, _doc_type = current_record_to_index(record) try: for r in current_search_client.search( index=clz.get_acl_index_name(index), **add_doc_type(current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME']), body=query )['hits']['hits']: yield clz.query.get(r['_id']) except elasticsearch.TransportError as e: logger.error('Error running ACL query on index %s, doctype %s, query %s', clz.get_acl_index_name(index), current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME'], query) if e.status_code == 404: raise RuntimeError('Explicit ACLs were not prepared for the given schema. ' 'Please run invenio explicit-acls prepare %s' % record.get('$schema', '')) else: # pragma: no cover raise
def index(self, record): """Indexing a record.""" return_value = super().index(record) index_name, doc_type = current_record_to_index(record) # TODO: Do we need to flush everytime the ES index? # Tests depends on this at the moment. current_search.flush_and_refresh(index_name) return return_value
def delete(self, record): """Delete a record. :param record: Record instance. """ return_value = super(IlsRecordIndexer, self).delete(record) index_name, doc_type = current_record_to_index(record) current_search.flush_and_refresh(index_name) return return_value
def delete(self, record): """Delete a record. :param record: Record to remove from index. :returns: Indexation result """ return_value = super(SonarIndexer, self).delete(record) index_name, doc_type = current_record_to_index(record) current_search.flush_and_refresh(index_name) return return_value
def index(self, record): """Indexing a record. :param record: Record to index. :returns: Indexation result """ return_value = super(SonarIndexer, self).index(record) index_name, doc_type = current_record_to_index(record) current_search.flush_and_refresh(index_name) return return_value
def index(self, record): """Indexing a record.""" return_value = super(IlsRecordIndexer, self).index(record) index_name, doc_type = current_record_to_index(record) current_search.flush_and_refresh(index_name) return return_value
def explain_impl(record, debug): """ Explains which ACLs will be applied to a record and what the added ACL property will look like. :param record a path to a file containing record metadata or '-' to read the metadata from stdin. """ class Model: def __init__(self): self.id = 'record-id' with open(record, 'r') if record is not "-" else sys.stdin as f: record_metadata = json.load(f) if '$schema' not in record_metadata: print('Please add $schema to record metadata') return invenio_record = Record(record_metadata) invenio_record.model = Model() schema = record_metadata['$schema'] if schema.startswith('http://') or schema.startswith('https://'): schema = current_jsonschemas.url_to_path(schema) print('Possible ACLs') for acl in ACL.query.all(): if schema in acl.schemas: print(' ', type(acl).__name__, acl) for k in dir(acl): if k.startswith('_'): continue if k in ('metadata', 'query'): continue val = getattr(acl, k) if not callable(val) and val: if isinstance(val, list): print(' %s = %s' % (k, [str(x) for x in val])) else: print(' %s = %s' % (k, val)) print() applicable_acls = [] for acl in current_explicit_acls.acl_models: print('Checking ACLs of type', acl) if debug and hasattr(acl, '_get_percolate_query'): index, _doc_type = current_record_to_index(invenio_record) index = acl.get_acl_index_name(index) doc_type = current_app.config[ 'INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME'] print( ' Will run percolate query on index %s and doc_type %s:' % (index, doc_type)) print('\n'.join(' ' + x for x in json.dumps(acl._get_percolate_query( invenio_record), indent=4).split('\n'))) found_acls = list(acl.get_record_acls(invenio_record)) for acl in found_acls: print(' found match: %s with priority of %s' % (acl, acl.priority)) for actor in acl.actors: print(' ', actor) applicable_acls.extend(found_acls) print() if not applicable_acls: print('The record is not matched by any ACLs') return matching_acls = list( current_explicit_acls.get_record_acls(invenio_record)) print( 'Of these, the following ACLs will be used (have the highest priority):' ) for acl in matching_acls: print(' ', acl) for actor in acl.actors: print(' ', actor) print() print('The ACLs will get serialized to the following element') print( json.dumps( { '_invenio_explicit_acls': current_explicit_acls.serialize_record_acls(matching_acls) }, indent=4))
def acl_changed_reindex(acl_id): """ ACL has been changed so reindex all the documents in the given index. :param acl_id: id of ACL instance """ logger.info('Reindexing started for ACL=%s', acl_id) timestamp = datetime.datetime.now(datetime.timezone.utc) acl = ACL.query.filter_by(id=acl_id).one_or_none() if not acl: # deleted in the meanwhile, so just return return # pragma no cover # make sure all indices are flushed so that no resource is obsolete in index for schema in acl.schemas: current_search_client.indices.refresh(index=schema_to_index(schema)[0]) current_search_client.indices.flush(index=schema_to_index(schema)[0]) indexer = RecordIndexer() updated_count = 0 removed_count = 0 indices_to_refresh = set() for id in acl.get_matching_resources(): try: rec = Record.get_record(id) indices_to_refresh.add(current_record_to_index(rec)[0]) except: # pragma no cover # record removed in the meanwhile by another thread/process, # indexer should have been called to remove it from ES # won't test this so pragma no cover continue try: indexer.index(rec) updated_count += 1 except Exception as e: # pragma no cover logger.exception('Error indexing ACL for resource %s: %s', id, e) # refresh the indices for index in indices_to_refresh: current_search_client.indices.refresh(index=index) current_search_client.indices.flush(index=index) indices_to_refresh = set() # reindex the resources those were indexed by this acl but no longer should be for id in acl.used_in_records(older_than_timestamp=timestamp): try: rec = Record.get_record(id) indices_to_refresh.add(current_record_to_index(rec)[0]) except NoResultFound: # pragma no cover continue except: # pragma no cover logger.exception('Unexpected exception in record reindexing') continue try: removed_count += 1 indexer.index(rec) except: # pragma no cover logger.exception('Error indexing ACL for obsolete resource %s', id) # refresh the indices for index in indices_to_refresh: current_search_client.indices.refresh(index=index) current_search_client.indices.flush(index=index) logger.info( 'Reindexing finished for ACL=%s, acl applied to %s records, acl removed from %s records', acl_id, updated_count, removed_count)