def delete_one_alias_for_did(self, alias, did): """ Delete one of this DID / GUID's aliases. """ with self.session as session: self.logger.info(f"Trying to delete alias {alias} for did {did}...") index_record = get_record_if_exists(did, session) if index_record is None: self.logger.warn(f"No record found for did {did}") raise NoRecordFound(did) # authorization try: resources = [u.resource for u in index_record.authz] auth.authorize("delete", resources) except AuthError as err: self.logger.warn( f"Auth error deleting alias {alias} for did {did}: User not authorized to delete one or more of these resources: {resources}" ) raise err # delete just this alias num_rows_deleted = ( session.query(IndexRecordAlias) .filter(IndexRecordAlias.did == did, IndexRecordAlias.name == alias) .delete(synchronize_session="evaluate") ) if num_rows_deleted == 0: self.logger.warn(f"No alias {alias} found for did {did}") raise NoRecordFound(alias) self.logger.info(f"Deleted alias {alias} for did {did}.")
def get_latest_version(self, did): ''' Get the lattest record version given did ''' ret = {} with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') query = session.query(IndexRecord) records = query.filter(IndexRecord.baseid == record.baseid) \ .order_by(IndexRecord.updated_date).all() if (not records): raise NoRecordFound('no record found') record = records[-1] rev = record.rev did = record.did form = record.form size = record.size file_name = record.file_name metadata = {m.key: m.value for m in record.index_metadata} version = record.version urls = [u.url for u in record.urls] hashes = {h.hash_type: h.hash_value for h in record.hashes} created_date = record.created_date.isoformat() updated_date = record.updated_date.isoformat() ret = { 'did': did, 'rev': rev, 'size': size, 'file_name': file_name, 'metadata': metadata, 'version': version, 'urls': urls, 'hashes': hashes, 'form': form, 'created_date': created_date, 'updated_date': updated_date, } return ret
def get_latest_version(self, did, has_version=None): """ Get the lattest record version given did """ with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() baseid = record.baseid except NoResultFound: baseid = did except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') query = session.query(IndexRecord) query = query.filter(IndexRecord.baseid == baseid) \ .order_by(IndexRecord.created_date.desc()) if has_version: query = query.filter(IndexRecord.version.isnot(None)) record = query.first() if (not record): raise NoRecordFound('no record found') return record.to_document_dict()
def get_all_versions(self, did): """ Get all record versions given did """ ret = dict() with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() baseid = record.baseid except NoResultFound: record = session.query(BaseVersion).filter_by(baseid=did).first() if not record: raise NoRecordFound('no record found') else: baseid = record.baseid except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') query = session.query(IndexRecord) records = query.filter(IndexRecord.baseid == baseid).all() for idx, record in enumerate(records): ret[idx] = record.to_document_dict() return ret
def get(self, did): ''' Gets a record given the record id. ''' with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') rev = record.rev form = record.form size = record.size urls = [u.url for u in record.urls] hashes = {h.hash_type: h.hash_value for h in record.hashes} ret = { 'did': did, 'rev': rev, 'size': size, 'urls': urls, 'hashes': hashes, 'form': form, } return ret
def update(self, did, rev, urls=None, file_name=None, version=None): ''' Updates an existing record with new values. ''' with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') if rev != record.rev: raise RevisionMismatch('revision mismatch') if urls is not None: record.urls = [ IndexRecordUrl(did=record.did, url=url) for url in urls ] if file_name is not None: record.file_name = file_name if version is not None: record.version = version record.rev = str(uuid.uuid4())[:8] session.add(record) return record.did, record.baseid, record.rev
def get_aliases_for_did(self, did): """ Gets the aliases for a did """ with self.session as session: self.logger.info(f"Trying to get all aliases for did {did}...") index_record = get_record_if_exists(did, session) if index_record is None: self.logger.warn(f"No record found for did {did}") raise NoRecordFound(did) query = session.query(IndexRecordAlias).filter(IndexRecordAlias.did == did) return [i.name for i in query]
def get_all_versions(self, did): ''' Get all record versions given did ''' ret = dict() with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') query = session.query(IndexRecord) records = query.filter(IndexRecord.baseid == record.baseid).all() for idx, record in enumerate(records): rev = record.rev did = record.did form = record.form size = record.size file_name = record.file_name version = record.version urls = [u.url for u in record.urls] hashes = {h.hash_type: h.hash_value for h in record.hashes} metadata = {m.key: m.value for m in record.index_metadata} created_date = record.created_date.isoformat() updated_date = record.updated_date.isoformat() ret[idx] = { 'did': did, 'rev': rev, 'size': size, 'file_name': file_name, 'metadata': metadata, 'version': version, 'urls': urls, 'hashes': hashes, 'form': form, 'created_date': created_date, 'updated_date': updated_date, } return ret
def get(self, did): """ Gets a record given the record id or baseid. If the given id is a baseid, it will return the latest version """ with self.session as session: query = session.query(IndexRecord) query = query.filter( or_(IndexRecord.did == did, IndexRecord.baseid == did) ).order_by(IndexRecord.created_date.desc()) record = query.first() if record is None: raise NoRecordFound('no record found') return record.to_document_dict()
def get_by_alias(self, alias): """ Gets a record given a record alias """ with self.session as session: try: record = ( session.query(IndexRecord) .filter(IndexRecord.aliases.any(name=alias)).one() ) except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') return record.to_document_dict()
def get(self, did): ''' Gets a record given the record id. ''' with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') baseid = record.baseid rev = record.rev form = record.form size = record.size file_name = record.file_name version = record.version urls = [u.url for u in record.urls] hashes = {h.hash_type: h.hash_value for h in record.hashes} metadata = {m.key: m.value for m in record.index_metadata} created_date = record.created_date.isoformat() updated_date = record.updated_date.isoformat() ret = { 'did': did, 'baseid': baseid, 'rev': rev, 'size': size, 'file_name': file_name, 'version': version, 'urls': urls, 'hashes': hashes, 'metadata': metadata, 'form': form, 'created_date': created_date, "updated_date": updated_date, } return ret
def replace_aliases_for_did(self, aliases, did): """ Replace all aliases for one DID / GUID with new aliases. """ with self.session as session: self.logger.info( f"Trying to replace aliases for did {did} with new aliases {aliases}..." ) index_record = get_record_if_exists(did, session) if index_record is None: self.logger.warn(f"No record found for did {did}") raise NoRecordFound(did) # authorization try: resources = [u.resource for u in index_record.authz] auth.authorize("update", resources) except AuthError as err: self.logger.warn( f"Auth error while replacing aliases for did {did}: User not authorized to update one or more of these resources: {resources}" ) raise err try: # delete this GUID's aliases session.query(IndexRecordAlias).filter( IndexRecordAlias.did == did ).delete(synchronize_session="evaluate") # add new aliases index_record_aliases = [ IndexRecordAlias(did=did, name=alias) for alias in aliases ] session.add_all(index_record_aliases) session.commit() self.logger.info( f"Replaced aliases for did {did} with new aliases {aliases}" ) except IntegrityError: # One or more aliases in request were non-unique self.logger.warn( f"One or more aliases in request already associated with another GUID: {aliases}" ) raise UserError( f"One or more aliases in request already associated with another GUID: {aliases}" )
def update_blank_record(self, did, rev, size, hashes, urls): """ Update a blank record with size and hashes, raise exception if the record is non-empty or the revision is not matched """ hashes = hashes or {} urls = urls or [] if not size or not hashes: raise UserError("No size or hashes provided") with self.session as session: query = session.query(IndexRecord).filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') if record.size or record.hashes: raise UserError("update api is not supported for non-empty record!") if rev != record.rev: raise RevisionMismatch('revision mismatch') record.size = size record.hashes = [IndexRecordHash( did=record.did, hash_type=h, hash_value=v, ) for h, v in hashes.items()] record.urls = [IndexRecordUrl( did=record.did, url=url, ) for url in urls] record.rev = str(uuid.uuid4())[:8] session.add(record) session.commit() return record.did, record.rev, record.baseid
def delete(self, did, rev): ''' Removes record if stored by backend. ''' with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') if rev != record.rev: raise RevisionMismatch('revision mismatch') session.delete(record)
def delete(self, did, rev): """ Removes record if stored by backend. """ with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound("no record found") except MultipleResultsFound: raise MultipleRecordsFound("multiple records found") if rev != record.rev: raise RevisionMismatch("revision mismatch") auth.authorize("delete", [u.resource for u in record.authz]) session.delete(record)
def update(self, did, rev, size=None, urls=None, hashes=None): ''' Updates an existing record with new values. ''' with self.session as session: query = session.query(IndexRecord) query = query.filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') if rev != record.rev: raise RevisionMismatch('revision mismatch') if size is not None: record.size = size if urls is not None: record.urls = [ IndexRecordUrl(did=record, url=url) for url in urls ] if hashes is not None: record.hashes = [ IndexRecordHash( did=record, hash_type=h, hash_value=v, ) for h, v in hashes.items() ] record.rev = str(uuid.uuid4())[:8] session.add(record) return record.did, record.rev
def append_aliases_for_did(self, aliases, did): """ Append one or more aliases to aliases already associated with one DID / GUID. """ with self.session as session: self.logger.info( f"Trying to append new aliases {aliases} to aliases for did {did}..." ) index_record = get_record_if_exists(did, session) if index_record is None: self.logger.warn(f"No record found for did {did}") raise NoRecordFound(did) # authorization try: resources = [u.resource for u in index_record.authz] auth.authorize("update", resources) except AuthError as err: self.logger.warn( f"Auth error while appending aliases to did {did}: User not authorized to update one or more of these resources: {resources}" ) raise err # add new aliases index_record_aliases = [ IndexRecordAlias(did=did, name=alias) for alias in aliases ] try: session.add_all(index_record_aliases) session.commit() except IntegrityError as err: # One or more aliases in request were non-unique self.logger.warn( f"One or more aliases in request already associated with this or another GUID: {aliases}" ) raise UserError( f"One or more aliases in request already associated with this or another GUID: {aliases}" )
def add_version(self, current_did, form, new_did=None, size=None, file_name=None, metadata=None, urls_metadata=None, version=None, urls=None, acl=None, hashes=None): """ Add a record version given did """ urls = urls or [] acl = acl or [] hashes = hashes or {} metadata = metadata or {} urls_metadata = urls_metadata or {} with self.session as session: query = session.query(IndexRecord).filter_by(did=current_did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') baseid = record.baseid record = IndexRecord() did = new_did or str(uuid.uuid4()) record.did = did record.baseid = baseid record.rev = str(uuid.uuid4())[:8] record.form = form record.size = size record.file_name = file_name record.version = version record.urls = [IndexRecordUrl( did=record.did, url=url, ) for url in urls] record.acl = [IndexRecordACE( did=record.did, ace=ace, ) for ace in set(acl)] record.hashes = [IndexRecordHash( did=record.did, hash_type=h, hash_value=v, ) for h, v in hashes.items()] record.index_metadata = [IndexRecordMetadata( did=record.did, key=m_key, value=m_value ) for m_key, m_value in metadata.items()] try: session.add(record) create_urls_metadata(urls_metadata, record, session) session.commit() except IntegrityError: raise UserError('{did} already exists'.format(did=did), 400) return record.did, record.baseid, record.rev
def update(self, did, rev, changing_fields): """ Updates an existing record with new values. """ composite_fields = ["urls", "acl", "authz", "metadata", "urls_metadata"] with self.session as session: query = session.query(IndexRecord).filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound("no record found") except MultipleResultsFound: raise MultipleRecordsFound("multiple records found") if rev != record.rev: raise RevisionMismatch("revision mismatch") auth.authorize("update", [u.resource for u in record.authz]) # Some operations are dependant on other operations. For example # urls has to be updated before urls_metadata because of schema # constraints. if "urls" in changing_fields: for url in record.urls: session.delete(url) record.urls = [ IndexRecordUrl(did=record.did, url=url) for url in changing_fields["urls"] ] if "acl" in changing_fields: for ace in record.acl: session.delete(ace) record.acl = [ IndexRecordACE(did=record.did, ace=ace) for ace in set(changing_fields["acl"]) ] if "authz" in changing_fields: for resource in record.authz: session.delete(resource) record.authz = [ IndexRecordAuthz(did=record.did, resource=resource) for resource in set(changing_fields["authz"]) ] if "metadata" in changing_fields: for md_record in record.index_metadata: session.delete(md_record) record.index_metadata = [ IndexRecordMetadata(did=record.did, key=m_key, value=m_value) for m_key, m_value in changing_fields["metadata"].items() ] if "urls_metadata" in changing_fields: for url in record.urls: for url_metadata in url.url_metadata: session.delete(url_metadata) create_urls_metadata(changing_fields["urls_metadata"], record, session) for key, value in changing_fields.items(): if key not in composite_fields: # No special logic needed for other updates. # ie file_name, version, etc setattr(record, key, value) record.rev = str(uuid.uuid4())[:8] session.add(record) return record.did, record.baseid, record.rev
def update(self, did, rev, changing_fields): """ Updates an existing record with new values. """ composite_fields = ['urls', 'acl', 'metadata', 'urls_metadata'] with self.session as session: query = session.query(IndexRecord).filter(IndexRecord.did == did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') if rev != record.rev: raise RevisionMismatch('revision mismatch') # Some operations are dependant on other operations. For example # urls has to be updated before urls_metadata because of schema # constraints. if 'urls' in changing_fields: for url in record.urls: session.delete(url) record.urls = [ IndexRecordUrl(did=record.did, url=url) for url in changing_fields['urls'] ] if 'acl' in changing_fields: for ace in record.acl: session.delete(ace) record.acl = [ IndexRecordACE(did=record.did, ace=ace) for ace in changing_fields['acl'] ] if 'metadata' in changing_fields: for md_record in record.index_metadata: session.delete(md_record) record.index_metadata = [ IndexRecordMetadata( did=record.did, key=m_key, value=m_value ) for m_key, m_value in changing_fields['metadata'].items()] if 'urls_metadata' in changing_fields: for url in record.urls: for url_metadata in url.url_metadata: session.delete(url_metadata) create_urls_metadata( changing_fields['urls_metadata'], record, session, ) for key, value in changing_fields.items(): if key not in composite_fields: # No special logic needed for other updates. # ie file_name, version, etc setattr(record, key, value) record.rev = str(uuid.uuid4())[:8] session.add(record) return record.did, record.baseid, record.rev
def add_version(self, did, form, size=None, file_name=None, metadata=None, version=None, urls=None, hashes=None): ''' Add a record version given did ''' if urls is None: urls = [] if hashes is None: hashes = {} if metadata is None: metadata = {} with self.session as session: query = session.query(IndexRecord).filter_by(did=did) try: record = query.one() except NoResultFound: raise NoRecordFound('no record found') except MultipleResultsFound: raise MultipleRecordsFound('multiple records found') baseid = record.baseid record = IndexRecord() did = str(uuid.uuid4()) record.did = did record.baseid = baseid record.rev = str(uuid.uuid4())[:8] record.form = form record.size = size record.file_name = file_name record.version = version record.urls = [ IndexRecordUrl( did=record.did, url=url, ) for url in urls ] record.hashes = [ IndexRecordHash( did=record.did, hash_type=h, hash_value=v, ) for h, v in hashes.items() ] record.index_metadata = [ IndexRecordMetadata(did=record.did, key=m_key, value=m_value) for m_key, m_value in metadata.items() ] try: session.add(record) session.commit() except IntegrityError: raise UserError('{did} already exists'.format(did=did), 400) return record.did, record.baseid, record.rev