def test_cli_full_reindex(app, db, es, capsys, es_acl_prepare, test_users): pid, record = create_record( { '$schema': RECORD_SCHEMA, 'keywords': ['blah'] }, clz=SchemaEnforcingRecord) RecordIndexer().index(record) current_search_client.indices.flush() with db.session.begin_nested(): acl = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'blah' }}) db.session.add(acl) u = UserActor(name='test', acl=acl, originator=test_users.u1, users=[test_users.u1]) db.session.add(u) # now the record is not indexed and ACL is not in the helper index, check it ... retrieved = RecordsSearch( index=schema_to_index(RECORD_SCHEMA)[0]).get_record( record.id).execute().hits[0].to_dict() assert '_invenio_explicit_acls' not in retrieved # just a precaution test assert current_explicit_acls.enabled_schemas == {RECORD_SCHEMA} # and run the reindex - should reindex one record from invenio_explicit_acls.cli import full_reindex_impl full_reindex_impl(verbose=True, records=True, in_bulk=False) captured = capsys.readouterr() assert captured.out.strip() == """ Reindexing ACLs Updating ACL representation for "test" (%s) on schemas ['records/record-v1.0.0.json'] Getting records for schema records/record-v1.0.0.json ... collected 1 records Adding 1 records to indexing queue""".strip() % (acl.id) current_search_client.indices.flush() retrieved = RecordsSearch( index=schema_to_index(RECORD_SCHEMA)[0]).get_record( record.id).execute().hits[0].to_dict() assert clear_timestamp(retrieved['_invenio_explicit_acls']) == [{ 'id': str(acl.id), 'operation': 'get', 'timestamp': 'cleared', 'user': [1] }]
def acl_deleted_reindex(schemas, acl_id): """ ACL has been deleted so reindex all the documents that contain reference to it. :param index: the index of documents :param record_acl_id: if of the ACL instance that has been deleted """ logger.info('Reindexing started for deleted ACL=%s', acl_id) acl = ACL.query.filter_by(id=acl_id).one_or_none() if acl: # pragma no cover raise AttributeError( 'ACL with id %s is still in the database, ' 'please remove it before calling current_explicit_acls.reindex_acl_removed' % acl_id) indexer = RecordIndexer() query = { "nested": { "path": "_invenio_explicit_acls", "query": { "term": { "_invenio_explicit_acls.id": acl_id } } } } removed_count = 0 for schema in schemas: current_search_client.indices.refresh(index=schema_to_index(schema)[0]) current_search_client.indices.flush(index=schema_to_index(schema)[0]) try: index, doc_type = schema_to_index(schema) for doc in elasticsearch.helpers.scan(current_search_client, query={ "query": query, "_source": False, }, index=index, **add_doc_type(doc_type)): try: indexer.index(Record.get_record(doc['_id'])) removed_count += 1 except NoResultFound: # pragma no cover continue except: # pragma no cover logger.exception( 'Unexpected exception in record reindexing') continue except: # pragma no cover logger.exception('Error removing ACL from schema %s', schema) logger.info( 'Reindexing finished for deleted ACL=%s, acl removed from %s records', acl_id, removed_count)
def test_propertyvalue_acl_prepare_schema_acl(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing PropertyValueACL.prepare_schema_acls(RECORD_SCHEMA) idx = PropertyValueACL.get_acl_index_name( schema_to_index(RECORD_SCHEMA)[0]) mapping = current_search_client.indices.get_mapping(idx) assert idx in mapping idx, doc_type = schema_to_index(RECORD_SCHEMA) mapping = current_search_client.indices.get_mapping(idx) assert '_invenio_explicit_acls' in mapping[idx]['mappings'][doc_type][ 'properties']
def test_create_record_check_acl_priority(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = SystemRoleActor(name='auth', system_role='any_user', acl=acl1, originator=test_users.u1) acl2 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=1, originator=test_users.u1, operation='get') actor2 = SystemRoleActor(name='auth', system_role='authenticated_user', acl=acl2, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) db.session.add(acl2) db.session.add(actor2) login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({ 'title': 'blah', 'contributors': [] }), content_type='application/json') assert response.status_code == 201 rest_metadata = get_json(response)['metadata'] assert 'control_number' in rest_metadata index, doctype = schema_to_index(RECORD_SCHEMA) rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) clear_timestamp(rec_md) assert rec_md['_source']['_invenio_explicit_acls'] == [{ 'operation': 'get', 'id': acl2.id, 'timestamp': 'cleared', 'system_role': ['authenticated_user'] }]
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().astimezone().isoformat() 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.flush(index=schema_to_index(schema)[0]) indexer = RecordIndexer() updated_count = 0 removed_count = 0 for id in acl.get_matching_resources(): try: rec = Record.get_record(id) 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) # 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) 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) logger.info( 'Reindexing finished for ACL=%s, acl applied to %s records, acl removed from %s records', acl_id, updated_count, removed_count)
def test_elasticsearch_acl_prepare_schema_acl(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing ElasticsearchACL.prepare_schema_acls(RECORD_SCHEMA) idx = ElasticsearchACL.get_acl_index_name( schema_to_index(RECORD_SCHEMA)[0]) mapping = current_search_client.indices.get_mapping(idx) assert idx in mapping idx, doc_type = schema_to_index(RECORD_SCHEMA) mapping = current_search_client.indices.get_mapping(idx) assert len(mapping) == 1 key = list(mapping.keys())[0] if ES_VERSION[0] < 7: assert '_invenio_explicit_acls' in mapping[key]['mappings'][doc_type][ 'properties'] else: assert '_invenio_explicit_acls' in mapping[key]['mappings'][ 'properties']
def prepare_schema_acls(self, schema): """ Prepare ACLs for the given index. :param schema: schema for which to prepare the ACLs """ index_name, doc_type = schema_to_index(schema) # create a new index where percolate queries will be stored acl_index_name = self.get_acl_index_name(index_name) # create mapping for acl index target_mapping_resource = current_search.mappings[index_name] with open(target_mapping_resource) as f: mapping = json.load(f) acl_doctype_name = current_explicit_acls.acl_doctype_name if 'properties' not in mapping['mappings']: # ES6-style mapping file fk = next(iter(mapping['mappings'].keys())) if acl_doctype_name != fk: mapping['mappings'][acl_doctype_name] = mapping['mappings'][fk] del mapping['mappings'][fk] mapping['mappings'][acl_doctype_name]['properties'] = { **mapping['mappings'][acl_doctype_name]['properties'], "__acl_record_selector": { "type": "percolator" }, "__acl_record_type": { "type": "keyword" } } else: # ES7 mapping file mapping['mappings']['properties'] = { **mapping['mappings']['properties'], "__acl_record_selector": { "type": "percolator" }, "__acl_record_type": { "type": "keyword" } } try: current_search_client.indices.create(index=acl_index_name, body=mapping) except Exception as e: logger.error('Error in creating index for ACLs: %s', e)
def test_propertyvalue_acl_delete(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing with db.session.begin_nested(): acl = PropertyValueACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1) propval = PropertyValue(name='keywords', value='test', acl=acl, originator=test_users.u1) db.session.add(acl) db.session.add(propval) acl.update() idx = acl.get_acl_index_name(schema_to_index(RECORD_SCHEMA)[0]) acl_md = current_search_client.get( index=idx, doc_type=current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME'], id=acl.id) # ES7 returns extra: acl_md.pop('_seq_no', None) acl_md.pop('_primary_term', None) assert acl_md == { '_id': acl.id, '_index': 'invenio_explicit_acls-acl-v1.0.0-records-record-v1.0.0', '_source': { '__acl_record_selector': { 'bool': { 'must': [{ 'term': { 'keywords': 'test' } }] } }, '__acl_record_type': 'propertyvalue' }, '_type': '_doc', '_version': 1, 'found': True } acl.delete() with pytest.raises(elasticsearch.exceptions.NotFoundError): current_search_client.get( index=idx, doc_type=current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME'], id=acl.id)
def delete(self): """Delete acl from any internal representation / index for the acl.""" for schema in self.schemas: acl_index_name = self.get_acl_index_name(schema_to_index(schema)[0]) try: return current_search_client.delete( index=acl_index_name, **add_doc_type(current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME']), id=self.id, refresh='wait_for' ) except: # pragma: no cover logger.exception('Strange, the ACL has not been indexed: %s', repr(self)) finally: current_search_client.indices.flush(index=acl_index_name)
def test_aclserializer(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = UserActor(name='auth', users=[test_users.u1], acl=acl1, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) pid, rec = create_record({'title': 'blah'}, clz=SchemaEnforcingRecord) RecordIndexer().index(rec) current_search_client.indices.flush() assert current_jsonschemas.url_to_path( rec['$schema']) in current_explicit_acls.enabled_schemas assert list(DefaultACL.get_record_acls(rec)) != [] index, doc_type = schema_to_index(RECORD_SCHEMA) data = current_search_client.get(index=index, doc_type=doc_type, id=str(pid.object_uuid))['_source'] assert '_invenio_explicit_acls' in data assert len(data['_invenio_explicit_acls']) == 1 with app.test_request_context(): login_user(test_users.u1) set_identity(test_users.u1) acljson_serializer = ACLJSONSerializer(RecordSchemaV1, acl_rest_endpoint='recid', replace_refs=True) serialized = json.loads(acljson_serializer.serialize(pid, rec)) assert serialized['invenio_explicit_acls'] == ["get"] with app.test_client() as client: login(client, test_users.u1) search_results = client.get(url_for('invenio_records_rest.recid_list')) search_results = get_json(search_results) hits = search_results['hits']['hits'] assert len(hits) == 1 assert hits[0]['invenio_explicit_acls'] == ["get"]
def get_matching_resources(self) -> Iterable[str]: """ Get resources that match the ACL. :param acl: the acl :return: iterable of resource ids """ for schema in self.schemas: index, doc_type = schema_to_index(schema) for r in current_search_client.search(index=index, **add_doc_type(doc_type), body={ "query": { "match_all": {} }, "_source": False, })['hits']['hits']: yield r['_id']
def used_in_records(self, older_than_timestamp=None): """ Returns IDs of all records that reference the ACL in cached acls in elasticsearch. :param older_than_timestamp: only restrict to records where the cached ACLs are older than the timestamp :return: An iterable of Record IDs """ for schema in self.schemas: index, doc_type = schema_to_index(schema) query = [{"term": {"_invenio_explicit_acls.id": str(self.id)}}] if older_than_timestamp: if isinstance(older_than_timestamp, datetime.datetime): older_than_timestamp = older_than_timestamp.isoformat() query.append({ "range": { "_invenio_explicit_acls.timestamp": { "lt": older_than_timestamp } } }) query = { "nested": { "path": "_invenio_explicit_acls", "score_mode": "min", "query": { "bool": { "must": query } } } } for doc in elasticsearch.helpers.scan(current_search_client, query={ "query": query, "_source": False, }, index=index, **add_doc_type(doc_type)): yield doc['_id']
def get_matching_resources(self) -> Iterable[str]: """ Get resources that match the ACL. :param acl: the acl :return: iterable of resource ids """ for schema in self.schemas: index_name, doc_type = schema_to_index(schema) try: for doc in elasticsearch.helpers.scan( current_search_client, query={ "query": self.record_selector, "_source": False, }, index=index_name, **add_doc_type(doc_type) ): yield doc['_id'] except: # pragma: no cover logger.exception('Error getting resources for schema %s', schema)
def test_elasticsearch_acl_update(app, db, es, es_acl_prepare, test_users): # should pass as it does nothing with db.session.begin_nested(): acl = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'test' }}) db.session.add(acl) acl.update() # makes version 1 acl.update() # makes version 2 idx = acl.get_acl_index_name(schema_to_index(RECORD_SCHEMA)[0]) acl_md = current_search_client.get( index=idx, doc_type=current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME'], id=acl.id) # ES7 returns extra: acl_md.pop('_seq_no', None) acl_md.pop('_primary_term', None) print(json.dumps(acl_md, indent=4)) assert acl_md == { '_id': acl.id, '_index': 'invenio_explicit_acls-acl-v1.0.0-records-record-v1.0.0', '_source': { '__acl_record_selector': { 'term': { 'keywords': 'test' } }, '__acl_record_type': 'elasticsearch' }, '_type': '_doc', '_version': 2, 'found': True }
def update(self): """Update any internal representation / index for the acl.""" body = { '__acl_record_selector': self.record_selector, '__acl_record_type': self.type } if logger.isEnabledFor(logging.DEBUG) <= logging.DEBUG: logger.debug('get_material_acls: query %s', json.dumps(body, indent=4, ensure_ascii=False)) schema_indices = [schema_to_index(x)[0] for x in self.schemas] acl_index_names = [self.get_acl_index_name(x) for x in schema_indices] for acl_idx_name in acl_index_names: try: resp = current_search_client.index( index=acl_idx_name, **add_doc_type(current_app.config['INVENIO_EXPLICIT_ACLS_DOCTYPE_NAME']), id=self.id, body=body, refresh='wait_for' ) assert resp['result'] in ('created', 'updated') finally: current_search_client.indices.flush(index=acl_idx_name)
def prepare(self, schema): """ Add ACL support for a given schema. This call goes through all registered ACL types and lets them do whatever preparation is needed (for example, creating extra indices in elasticsearch). Then it adds _invenio_explicit_acls field to the elasticsearch index for the given schema that wil store preprocessed explicit ACLs for each record :param schema: schema URL of the schema that should be patched with ACL support """ # let each acl model to prepare the schema if needed for model in self.acl_models: model.prepare_schema_acls(schema) # add an extra column containing preprocessed ACLs to the prepared schema index_name, doc_type = schema_to_index(schema) # print(json.dumps(self._extra_mapping, indent=4)) current_search_client.indices.put_mapping(index=index_name, doc_type=doc_type, body=self._extra_mapping)
def get_from_es(pid, schema='records/record-v1.0.0.json'): """Retrieves a record from elasticsearch.""" index, doctype = schema_to_index(schema) return current_search_client.get(index=index, doc_type=doctype, id=pid.object_uuid)
def test_aclrecordsearch_returnall(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl1 = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'test' }}) actor1 = SystemRoleActor(name='auth', system_role='any_user', acl=acl1, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) current_explicit_acls.reindex_acl(acl1, delayed=False) with app.test_client() as client: login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({'title': 'blah', 'contributors': [], 'keywords': ['blah']}), content_type='application/json') assert response.status_code == 201 rest_metadata = get_json(response)['metadata'] assert 'control_number' in rest_metadata # make sure indices are flushed current_search_client.indices.refresh() current_search_client.indices.flush() index, doc_type = schema_to_index(RECORD_SCHEMA) record_uuid = PersistentIdentifier.get('recid', rest_metadata['control_number']).object_uuid with app.test_request_context(): login_user(test_users.u1) set_identity(test_users.u1) assert current_user == test_users.u1 # acl1 does not apply to the resource so the search must return no data assert not len( ACLRecordsSearch(index=index, doc_type=doc_type, operation='get').get_record(record_uuid).execute()) # when acl_return_all is specified, return all matching records regardless of ACL with_all = ACLRecordsSearch(index=index, doc_type=doc_type).acl_return_all().get_record( record_uuid).execute().hits assert len(with_all) == 1 assert with_all[0]['_invenio_explicit_acls'] == [] # add another acl, this one maps to the record with db.session.begin_nested(): acl2 = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'blah' }}) actor2 = UserActor(name='u2', users=[test_users.u2], acl=acl2, originator=test_users.u1) db.session.add(acl2) db.session.add(actor2) current_explicit_acls.reindex_acl(acl2, delayed=False) # make sure indices are flushed current_search_client.indices.refresh() current_search_client.indices.flush() # for the same user acl_return_all() must return the record and effective acls with app.test_request_context(): login_user(test_users.u1) set_identity(test_users.u1) # when acl_return_all is specified, return all matching records regardless of ACL with_all = ACLRecordsSearch(index=index, doc_type=doc_type).acl_return_all().get_record( record_uuid).execute().hits assert len(with_all) == 1 assert clear_timestamp(with_all[0].to_dict()['_invenio_explicit_acls']) == [ { 'operation': 'get', 'id': acl2.id, 'timestamp': 'cleared', 'user': [2] } ] # for user2 plain ACLRecordsSearch must return the record and effective acls with app.test_request_context(): login_user(test_users.u2) set_identity(test_users.u2) # when acl_return_all is specified, return all matching records regardless of ACL with_all = ACLRecordsSearch(index=index, doc_type=doc_type).get_record(record_uuid).execute().hits assert len(with_all) == 1 assert clear_timestamp(with_all[0].to_dict()['_invenio_explicit_acls']) == [ { 'operation': 'get', 'id': acl2.id, 'timestamp': 'cleared', 'user': [2] } ]
def test_change_acl_mapping(app, db, es, es_acl_prepare, test_users): pid, record = create_record({'$schema': RECORD_SCHEMA, 'keywords': ['blah']}, clz=SchemaEnforcingRecord) pid1, record1 = create_record({'$schema': RECORD_SCHEMA, 'keywords': ['test']}, clz=SchemaEnforcingRecord) RecordIndexer().index(record) RecordIndexer().index(record1) current_search_client.indices.flush() with db.session.begin_nested(): acl = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'blah' }}) actor = UserActor(users=[test_users.u1], acl=acl, originator=test_users.u1) db.session.add(acl) db.session.add(actor) current_explicit_acls.reindex_acl(acl, delayed=False) current_search_client.indices.flush() index, doc_type = schema_to_index(RECORD_SCHEMA) hits = current_search_client.search( index=index, doc_type=doc_type, body={ 'query': { 'nested': { 'path': '_invenio_explicit_acls', 'query': { 'term': { '_invenio_explicit_acls.id': str(acl.id) } } } }, '_source': False } )['hits']['hits'] assert len(hits) == 1 assert hits[0]['_id'] == str(pid.object_uuid) with db.session.begin_nested(): acl.record_selector = { 'term': { 'keywords': 'test' } } db.session.add(acl) current_explicit_acls.reindex_acl(acl, delayed=False) current_search_client.indices.flush() hits = current_search_client.search( index=index, doc_type=doc_type, body={ 'query': { 'nested': { 'path': '_invenio_explicit_acls', 'query': { 'term': { '_invenio_explicit_acls.id': str(acl.id) } } } }, '_source': False } )['hits']['hits'] assert len(hits) == 1 assert hits[0]['_id'] == str(pid1.object_uuid)
def test_used_in_records(app, db, es, es_acl_prepare, test_users): with db.session.begin_nested(): acl1 = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'blah' }}) actor1 = SystemRoleActor(name='auth', acl=acl1, originator=test_users.u1, system_role='authenticated_user') db.session.add(acl1) db.session.add(actor1) acl2 = ElasticsearchACL(name='test', schemas=[RECORD_SCHEMA], priority=0, operation='get', originator=test_users.u1, record_selector={'term': { 'keywords': 'test' }}) actor2 = SystemRoleActor(name='noauth', acl=acl2, originator=test_users.u1, system_role='any_user') db.session.add(actor2) db.session.add(acl2) acl1.update() acl2.update() pid1, record1 = create_record( { '$schema': RECORD_SCHEMA, 'keywords': ['blah'] }, clz=SchemaEnforcingRecord) pid2, record2 = create_record( { '$schema': RECORD_SCHEMA, 'keywords': ['test'] }, clz=SchemaEnforcingRecord) ts1 = datetime.datetime.now(datetime.timezone.utc) time.sleep(0.1) RecordIndexer().index(record1) current_search_client.indices.refresh() current_search_client.indices.flush() time.sleep(1) ts2 = datetime.datetime.now(datetime.timezone.utc) time.sleep(0.1) RecordIndexer().index(record2) current_search_client.indices.refresh() current_search_client.indices.flush() time.sleep(1) ts3 = datetime.datetime.now(datetime.timezone.utc) # the records should have cached ACLs, let's check idx, doc_type = schema_to_index(RECORD_SCHEMA) assert clear_timestamp( current_search_client.get( index=idx, doc_type=doc_type, id=str(record1.id))['_source']['_invenio_explicit_acls']) == [{ 'operation': 'get', 'id': acl1.id, 'timestamp': 'cleared', 'system_role': ['authenticated_user'] }] assert clear_timestamp( current_search_client.get( index=idx, doc_type=doc_type, id=str(record2.id))['_source']['_invenio_explicit_acls']) == [{ 'operation': 'get', 'id': acl2.id, 'timestamp': 'cleared', 'system_role': ['any_user'] }] # there should be no resource for acl1 before ts1 assert list(acl1.used_in_records(older_than_timestamp=ts1)) == [] # one record before ts2 and ts3 assert list( acl1.used_in_records(older_than_timestamp=ts2)) == [str(record1.id)] assert list( acl1.used_in_records(older_than_timestamp=ts3)) == [str(record1.id)] # and one record before now assert list(acl1.used_in_records()) == [str(record1.id)] # there should be no resource for acl2 before ts1 and ts2 assert list(acl2.used_in_records(older_than_timestamp=ts1)) == [] assert list(acl2.used_in_records(older_than_timestamp=ts2)) == [] # one record before ts3 assert list( acl2.used_in_records(older_than_timestamp=ts3)) == [str(record2.id)] # and one record before now assert list(acl2.used_in_records()) == [str(record2.id)]
def test_create_acl_after_record(app, db, es, es_acl_prepare, test_users): with app.test_client() as client: login(client, test_users.u1) response = client.post(records_url(), data=json.dumps({ 'title': 'blah', 'contributors': [] }), content_type='application/json') assert response.status_code == 201 rest_metadata = get_json(response)['metadata'] assert 'control_number' in rest_metadata current_search_client.indices.refresh() current_search_client.indices.flush() with db.session.begin_nested(): acl1 = DefaultACL(name='default', schemas=[RECORD_SCHEMA], priority=0, originator=test_users.u1, operation='get') actor1 = SystemRoleActor(name='auth', system_role='any_user', acl=acl1, originator=test_users.u1) db.session.add(acl1) db.session.add(actor1) # reindex all resources that might be affected by the ACL change current_explicit_acls.reindex_acl(acl1, delayed=False) index, doctype = schema_to_index(RECORD_SCHEMA) rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) clear_timestamp(rec_md) assert rec_md['_source']['_invenio_explicit_acls'] == [{ 'operation': 'get', 'id': acl1.id, 'timestamp': 'cleared', 'system_role': ['any_user'] }] # remove the ACL from the database with db.session.begin_nested(): db.session.delete(acl1) # reindex records affected by the removal of ACL current_explicit_acls.reindex_acl_removed(acl1, delayed=False) # make sure all changes had time to propagate and test current_search_client.indices.refresh() current_search_client.indices.flush() rec_md = current_search_client.get( index=index, doc_type=doctype, id=str( PersistentIdentifier.get( 'recid', rest_metadata['control_number']).object_uuid)) # there is no ACL in the database => no acls are defined nor enforced on the record print(json.dumps(rec_md, indent=4)) assert '_invenio_explicit_acls' not in rec_md['_source']