async def write_datacite_metadata(guid, temp_dir): data = get_with_retry( f"{settings.OSF_API_URL}v2/registrations/{guid}/identifiers/" ).json()["data"] doi = [ identifier["attributes"]["value"] for identifier in data if identifier["attributes"]["category"] == "doi" ] if not doi: raise DataCiteNotFoundError( f"Datacite DOI not found for registration {guid} on OSF server." ) else: doi = doi[0] client = DataCiteMDSClient( url=settings.DATACITE_URL, username=settings.DATACITE_USERNAME, password=settings.DATACITE_PASSWORD, prefix=settings.DATACITE_PREFIX, ) try: xml_metadata = client.metadata_get(doi) except DataCiteNotFoundError: raise DataCiteNotFoundError( f"Datacite DOI not found for registration {guid} on Datacite server." ) with open(os.path.join(temp_dir, "datacite.xml"), "w") as fp: fp.write(xml_metadata) return xml_metadata
async def write_datacite_metadata(guid, temp_dir, metadata): try: doi = next(( identifier["attributes"]["value"] for identifier in metadata["data"]["embeds"]["identifiers"]["data"] if identifier["attributes"]["category"] == "doi")) except StopIteration: raise DataCiteNotFoundError( f"Datacite DOI not found for registration {guid} on OSF server.") client = DataCiteMDSClient( url=settings.DATACITE_URL, username=settings.DATACITE_USERNAME, password=settings.DATACITE_PASSWORD, prefix=settings.DATACITE_PREFIX, ) try: xml_metadata = client.metadata_get(doi) except DataCiteNotFoundError: raise DataCiteNotFoundError( f"Datacite DOI {doi} not found for registration {guid} on Datacite server." ) with open(os.path.join(temp_dir, "datacite.xml"), "w") as fp: fp.write(xml_metadata) return xml_metadata
def get_datacite_metadata(doi): client = DataCiteMDSClient( url=settings.DATACITE_URL, username=settings.DATACITE_USERNAME, password=settings.DATACITE_PASSWORD, prefix=settings.DATACITE_PREFIX, ) return client.metadata_get(doi)
def get_datacite_metadata(doi, datacite_username, datacite_password, datacite_prefix): assert isinstance(datacite_password, str), 'Datacite password not passed to pigeon' assert isinstance(datacite_username, str), 'Datacite username not passed to pigeon' assert isinstance(datacite_prefix, str), 'Datacite prefix not passed to pigeon' client = DataCiteMDSClient( url=settings.DATACITE_URL, username=datacite_username, password=datacite_password, prefix=datacite_prefix, ) return client.metadata_get(doi)
class DataCiteProvider(BaseProvider): """DOI provider using DataCite API.""" pid_type = 'doi' """Default persistent identifier type.""" pid_provider = 'datacite' """Persistent identifier provider name.""" default_status = PIDStatus.NEW """Default status for newly created PIDs by this provider.""" @classmethod def create(cls, pid_value, **kwargs): """Create a new record identifier. For more information about parameters, see :meth:`invenio_pidstore.providers.BaseProvider.create`. :param pid_value: Persistent identifier value. :params **kwargs: See :meth:`invenio_pidstore.providers.base.BaseProvider.create` extra parameters. :returns: A :class:`invenio_pidstore.providers.DataCiteProvider` instance. """ return super(DataCiteProvider, cls).create( pid_value=pid_value, **kwargs) def __init__(self, pid, client=None): """Initialize provider. To use the default client, just configure the following variables: * `PIDSTORE_DATACITE_USERNAME` as username. * `PIDSTORE_DATACITE_PASSWORD` as password. * `PIDSTORE_DATACITE_DOI_PREFIX` as DOI prefix. * `PIDSTORE_DATACITE_TESTMODE` to `True` if it configured in test mode. * `PIDSTORE_DATACITE_URL` as DataCite URL. :param pid: A :class:`invenio_pidstore.models.PersistentIdentifier` instance. :param client: A client to access to DataCite. (Default: :class:`datacite.DataCiteMDSClient` instance) """ super(DataCiteProvider, self).__init__(pid) if client is not None: self.api = client else: self.api = DataCiteMDSClient( username=current_app.config.get('PIDSTORE_DATACITE_USERNAME'), password=current_app.config.get('PIDSTORE_DATACITE_PASSWORD'), prefix=current_app.config.get('PIDSTORE_DATACITE_DOI_PREFIX'), test_mode=current_app.config.get( 'PIDSTORE_DATACITE_TESTMODE', False), url=current_app.config.get('PIDSTORE_DATACITE_URL')) def reserve(self, doc): """Reserve a DOI (amounts to upload metadata, but not to mint). :param doc: Set metadata for DOI. :returns: `True` if is reserved successfully. """ # Only registered PIDs can be updated. try: self.pid.reserve() self.api.metadata_post(doc) except (DataCiteError, HttpError): logger.exception("Failed to reserve in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully reserved in DataCite", extra=dict(pid=self.pid)) return True def register(self, url, doc): """Register a DOI via the DataCite API. :param url: Specify the URL for the API. :param doc: Set metadata for DOI. :returns: `True` if is registered successfully. """ try: self.pid.register() # Set metadata for DOI self.api.metadata_post(doc) # Mint DOI self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to register in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully registered in DataCite", extra=dict(pid=self.pid)) return True def update(self, url, doc): """Update metadata associated with a DOI. This can be called before/after a DOI is registered. :param doc: Set metadata for DOI. :returns: `True` if is updated successfully. """ if self.pid.is_deleted(): logger.info("Reactivate in DataCite", extra=dict(pid=self.pid)) try: # Set metadata self.api.metadata_post(doc) self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to update in DataCite", extra=dict(pid=self.pid)) raise if self.pid.is_deleted(): self.pid.sync_status(PIDStatus.REGISTERED) logger.info("Successfully updated in DataCite", extra=dict(pid=self.pid)) return True def delete(self): """Delete a registered DOI. If the PID is new then it's deleted only locally. Otherwise, also it's deleted also remotely. :returns: `True` if is deleted successfully. """ try: if self.pid.is_new(): self.pid.delete() else: self.pid.delete() self.api.metadata_delete(self.pid.pid_value) except (DataCiteError, HttpError): logger.exception("Failed to delete in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully deleted in DataCite", extra=dict(pid=self.pid)) return True def sync_status(self): """Synchronize DOI status DataCite MDS. :returns: `True` if is sync successfully. """ status = None try: try: self.api.doi_get(self.pid.pid_value) status = PIDStatus.REGISTERED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass if status is None: try: self.api.metadata_get(self.pid.pid_value) status = PIDStatus.RESERVED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass except (DataCiteError, HttpError): logger.exception("Failed to sync status from DataCite", extra=dict(pid=self.pid)) raise if status is None: status = PIDStatus.NEW self.pid.sync_status(status) logger.info("Successfully synced status from DataCite", extra=dict(pid=self.pid)) return True
class DataCiteProvider(BaseProvider): """DOI provider using DataCite API.""" pid_type = 'doi' """Default persistent identifier type.""" pid_provider = 'datacite' """Persistent identifier provider name.""" default_status = PIDStatus.NEW """Default status for newly created PIDs by this provider.""" @classmethod def create(cls, pid_value, **kwargs): """Create a new record identifier. For more information about parameters, see :meth:`invenio_pidstore.providers.base.BaseProvider.create`. :param pid_value: Persistent identifier value. :params ``**kwargs``: See :meth:`invenio_pidstore.providers.base.BaseProvider.create` extra parameters. :returns: A :class:`invenio_pidstore.providers.datacite.DataCiteProvider` instance. """ return super(DataCiteProvider, cls).create( pid_value=pid_value, **kwargs) def __init__(self, pid, client=None): """Initialize provider. To use the default client, just configure the following variables: * `PIDSTORE_DATACITE_USERNAME` as username. * `PIDSTORE_DATACITE_PASSWORD` as password. * `PIDSTORE_DATACITE_DOI_PREFIX` as DOI prefix. * `PIDSTORE_DATACITE_TESTMODE` to `True` if it configured in test mode. * `PIDSTORE_DATACITE_URL` as DataCite URL. :param pid: A :class:`invenio_pidstore.models.PersistentIdentifier` instance. :param client: A client to access to DataCite. (Default: :class:`datacite.DataCiteMDSClient` instance) """ super(DataCiteProvider, self).__init__(pid) if client is not None: self.api = client else: self.api = DataCiteMDSClient( username=current_app.config.get('PIDSTORE_DATACITE_USERNAME'), password=current_app.config.get('PIDSTORE_DATACITE_PASSWORD'), prefix=current_app.config.get('PIDSTORE_DATACITE_DOI_PREFIX'), test_mode=current_app.config.get( 'PIDSTORE_DATACITE_TESTMODE', False), url=current_app.config.get('PIDSTORE_DATACITE_URL')) def reserve(self, doc): """Reserve a DOI (amounts to upload metadata, but not to mint). :param doc: Set metadata for DOI. :returns: `True` if is reserved successfully. """ # Only registered PIDs can be updated. try: self.pid.reserve() self.api.metadata_post(doc) except (DataCiteError, HttpError): logger.exception("Failed to reserve in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully reserved in DataCite", extra=dict(pid=self.pid)) return True def register(self, url, doc): """Register a DOI via the DataCite API. :param url: Specify the URL for the API. :param doc: Set metadata for DOI. :returns: `True` if is registered successfully. """ try: self.pid.register() # Set metadata for DOI self.api.metadata_post(doc) # Mint DOI self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to register in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully registered in DataCite", extra=dict(pid=self.pid)) return True def update(self, url, doc): """Update metadata associated with a DOI. This can be called before/after a DOI is registered. :param doc: Set metadata for DOI. :returns: `True` if is updated successfully. """ if self.pid.is_deleted(): logger.info("Reactivate in DataCite", extra=dict(pid=self.pid)) try: # Set metadata self.api.metadata_post(doc) self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to update in DataCite", extra=dict(pid=self.pid)) raise if self.pid.is_deleted(): self.pid.sync_status(PIDStatus.REGISTERED) logger.info("Successfully updated in DataCite", extra=dict(pid=self.pid)) return True def delete(self): """Delete a registered DOI. If the PID is new then it's deleted only locally. Otherwise, also it's deleted also remotely. :returns: `True` if is deleted successfully. """ try: if self.pid.is_new(): self.pid.delete() else: self.pid.delete() self.api.metadata_delete(self.pid.pid_value) except (DataCiteError, HttpError): logger.exception("Failed to delete in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully deleted in DataCite", extra=dict(pid=self.pid)) return True def sync_status(self): """Synchronize DOI status DataCite MDS. :returns: `True` if is sync successfully. """ status = None try: try: self.api.doi_get(self.pid.pid_value) status = PIDStatus.REGISTERED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass if status is None: try: self.api.metadata_get(self.pid.pid_value) status = PIDStatus.RESERVED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass except (DataCiteError, HttpError): logger.exception("Failed to sync status from DataCite", extra=dict(pid=self.pid)) raise if status is None: status = PIDStatus.NEW self.pid.sync_status(status) logger.info("Successfully synced status from DataCite", extra=dict(pid=self.pid)) return True
username='******', password='******', prefix='10.5072', ) # Set metadata for DOI d.metadata_post(doc) # Mint new DOI d.doi_post('10.5072/test-doi', 'http://example.org/test-doi') # Get DOI location location = d.doi_get("10.5072/test-doi") # Set alternate URL for content type (available through content negotiation) d.media_post( "10.5072/test-doi", {"application/json": "http://example.org/test-doi/json/", "application/xml": "http://example.org/test-doi/xml/"} ) # Get alternate URLs mapping = d.media_get("10.5072/test-doi") assert mapping["application/json"] == "http://example.org/test-doi/json/" # Get metadata for DOI doc = d.metadata_get("10.5072/test-doi") # Make DOI inactive d.metadata_delete("10.5072/test-doi")
class DataCite(PidProvider): """DOI provider using DataCite API.""" pid_type = 'doi' def __init__(self): """Initialize provider.""" self.api = DataCiteMDSClient( username=cfg.get('CFG_DATACITE_USERNAME'), password=cfg.get('CFG_DATACITE_PASSWORD'), prefix=cfg.get('CFG_DATACITE_DOI_PREFIX'), test_mode=cfg.get('CFG_DATACITE_TESTMODE', False), url=cfg.get('CFG_DATACITE_URL') ) def _get_url(self, kwargs): try: return kwargs['url'] except KeyError: raise Exception("url keyword argument must be specified.") def _get_doc(self, kwargs): try: return kwargs['doc'] except KeyError: raise Exception("doc keyword argument must be specified.") def reserve(self, pid, *args, **kwargs): """Reserve a DOI (amounts to upload metadata, but not to mint).""" # Only registered PIDs can be updated. doc = self._get_doc(kwargs) try: self.api.metadata_post(doc) except DataCiteError as e: pid.log("RESERVE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("RESERVE", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("RESERVE", "Successfully reserved in DataCite") return True def register(self, pid, *args, **kwargs): """Register a DOI via the DataCite API.""" url = self._get_url(kwargs) doc = self._get_doc(kwargs) try: # Set metadata for DOI self.api.metadata_post(doc) # Mint DOI self.api.doi_post(pid.pid_value, url) except DataCiteError as e: pid.log("REGISTER", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("REGISTER", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("REGISTER", "Successfully registered in DataCite") return True def update(self, pid, *args, **kwargs): """Update metadata associated with a DOI. This can be called before/after a DOI is registered. """ url = self._get_url(kwargs) doc = self._get_doc(kwargs) if pid.is_deleted(): pid.log("UPDATE", "Reactivate in DataCite") try: # Set metadata self.api.metadata_post(doc) self.api.doi_post(pid.pid_value, url) except DataCiteError as e: pid.log("UPDATE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("UPDATE", "Failed with HttpError - %s" % unicode(e)) return False else: if pid.is_deleted(): pid.log( "UPDATE", "Successfully updated and possibly registered in DataCite" ) else: pid.log("UPDATE", "Successfully updated in DataCite") return True def delete(self, pid, *args, **kwargs): """Delete a registered DOI.""" try: self.api.metadata_delete(pid.pid_value) except DataCiteError as e: pid.log("DELETE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("DELETE", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("DELETE", "Successfully deleted in DataCite") return True def sync_status(self, pid, *args, **kwargs): """Synchronize DOI status DataCite MDS.""" status = None try: self.api.doi_get(pid.pid_value) status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteGoneError: status = cfg['PIDSTORE_STATUS_DELETED'] except DataCiteNoContentError: status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteNotFoundError: pass except DataCiteError as e: pid.log("SYNC", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("SYNC", "Failed with HttpError - %s" % unicode(e)) return False if status is None: try: self.api.metadata_get(pid.pid_value) status = cfg['PIDSTORE_STATUS_RESERVED'] except DataCiteGoneError: status = cfg['PIDSTORE_STATUS_DELETED'] except DataCiteNoContentError: status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteNotFoundError: pass except DataCiteError as e: pid.log("SYNC", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("SYNC", "Failed with HttpError - %s" % unicode(e)) return False if status is None: status = cfg['PIDSTORE_STATUS_NEW'] if pid.status != status: pid.log( "SYNC", "Fixed status from %s to %s." % (pid.status, status) ) pid.status = status return True @classmethod def is_provider_for_pid(cls, pid_str): """Check if DataCite is the provider for this DOI. Note: If you e.g. changed DataCite account and received a new prefix, then this provider can only update and register DOIs for the new prefix. """ return pid_str.startswith("%s/" % cfg['CFG_DATACITE_DOI_PREFIX'])
password='******', prefix='10.1234', test_mode=True, ) # Set metadata for DOI d.metadata_post(doc) # Mint new DOI d.doi_post('10.1234/test-doi', 'http://example.org/test-doi') # Get DOI location location = d.doi_get("10.1234/test-doi") # Set alternate URL for content type (available through content negotiation) d.media_post( "10.1234/test-doi", { "application/json": "http://example.org/test-doi/json/", "application/xml": "http://example.org/test-doi/xml/" }) # Get alternate URLs mapping = d.media_get("10.1234/test-doi") assert mapping["application/json"] == "http://example.org/test-doi/json/" # Get metadata for DOI doc = d.metadata_get("10.1234/test-doi") # Make DOI inactive d.metadata_delete("10.1234/test-doi")
class DataCite(PidProvider): """DOI provider using DataCite API.""" pid_type = 'doi' def __init__(self): """Initialize provider.""" self.api = DataCiteMDSClient(username=cfg.get('CFG_DATACITE_USERNAME'), password=cfg.get('CFG_DATACITE_PASSWORD'), prefix=cfg.get('CFG_DATACITE_DOI_PREFIX'), test_mode=cfg.get('CFG_DATACITE_TESTMODE', False), url=cfg.get('CFG_DATACITE_URL')) def _get_url(self, kwargs): try: return kwargs['url'] except KeyError: raise Exception("url keyword argument must be specified.") def _get_doc(self, kwargs): try: return kwargs['doc'] except KeyError: raise Exception("doc keyword argument must be specified.") def reserve(self, pid, *args, **kwargs): """Reserve a DOI (amounts to upload metadata, but not to mint).""" # Only registered PIDs can be updated. doc = self._get_doc(kwargs) try: self.api.metadata_post(doc) except DataCiteError as e: pid.log("RESERVE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("RESERVE", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("RESERVE", "Successfully reserved in DataCite") return True def register(self, pid, *args, **kwargs): """Register a DOI via the DataCite API.""" url = self._get_url(kwargs) doc = self._get_doc(kwargs) try: # Set metadata for DOI self.api.metadata_post(doc) # Mint DOI self.api.doi_post(pid.pid_value, url) except DataCiteError as e: pid.log("REGISTER", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("REGISTER", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("REGISTER", "Successfully registered in DataCite") return True def update(self, pid, *args, **kwargs): """Update metadata associated with a DOI. This can be called before/after a DOI is registered. """ url = self._get_url(kwargs) doc = self._get_doc(kwargs) if pid.is_deleted(): pid.log("UPDATE", "Reactivate in DataCite") try: # Set metadata self.api.metadata_post(doc) self.api.doi_post(pid.pid_value, url) except DataCiteError as e: pid.log("UPDATE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("UPDATE", "Failed with HttpError - %s" % unicode(e)) return False else: if pid.is_deleted(): pid.log( "UPDATE", "Successfully updated and possibly registered in DataCite") else: pid.log("UPDATE", "Successfully updated in DataCite") return True def delete(self, pid, *args, **kwargs): """Delete a registered DOI.""" try: self.api.metadata_delete(pid.pid_value) except DataCiteError as e: pid.log("DELETE", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("DELETE", "Failed with HttpError - %s" % unicode(e)) return False else: pid.log("DELETE", "Successfully deleted in DataCite") return True def sync_status(self, pid, *args, **kwargs): """Synchronize DOI status DataCite MDS.""" status = None try: self.api.doi_get(pid.pid_value) status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteGoneError: status = cfg['PIDSTORE_STATUS_DELETED'] except DataCiteNoContentError: status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteNotFoundError: pass except DataCiteError as e: pid.log("SYNC", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("SYNC", "Failed with HttpError - %s" % unicode(e)) return False if status is None: try: self.api.metadata_get(pid.pid_value) status = cfg['PIDSTORE_STATUS_RESERVED'] except DataCiteGoneError: status = cfg['PIDSTORE_STATUS_DELETED'] except DataCiteNoContentError: status = cfg['PIDSTORE_STATUS_REGISTERED'] except DataCiteNotFoundError: pass except DataCiteError as e: pid.log("SYNC", "Failed with %s" % e.__class__.__name__) return False except HttpError as e: pid.log("SYNC", "Failed with HttpError - %s" % unicode(e)) return False if status is None: status = cfg['PIDSTORE_STATUS_NEW'] if pid.status != status: pid.log("SYNC", "Fixed status from %s to %s." % (pid.status, status)) pid.status = status return True @classmethod def is_provider_for_pid(cls, pid_str): """Check if DataCite is the provider for this DOI. Note: If you e.g. changed DataCite account and received a new prefix, then this provider can only update and register DOIs for the new prefix. """ return pid_str.startswith("%s/" % cfg['CFG_DATACITE_DOI_PREFIX'])
class DataCiteProvider(BaseProvider): """DOI provider using DataCite API.""" pid_type = 'doi' pid_provider = 'datacite' default_status = PIDStatus.NEW @classmethod def create(cls, pid_value, **kwargs): """Create a new record identifier.""" return super(DataCiteProvider, cls).create( pid_value=pid_value, **kwargs) def __init__(self, pid, client=None): """Initialize provider.""" super(DataCiteProvider, self).__init__(pid) if client is not None: self.api = client else: self.api = DataCiteMDSClient( username=current_app.config.get('PIDSTORE_DATACITE_USERNAME'), password=current_app.config.get('PIDSTORE_DATACITE_PASSWORD'), prefix=current_app.config.get('PIDSTORE_DATACITE_DOI_PREFIX'), test_mode=current_app.config.get( 'PIDSTORE_DATACITE_TESTMODE', False), url=current_app.config.get('PIDSTORE_DATACITE_URL')) def reserve(self, doc): """Reserve a DOI (amounts to upload metadata, but not to mint).""" # Only registered PIDs can be updated. try: self.pid.reserve() self.api.metadata_post(doc) except (DataCiteError, HttpError): logger.exception("Failed to reserve in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully reserved in DataCite", extra=dict(pid=self.pid)) return True def register(self, url, doc): """Register a DOI via the DataCite API.""" try: self.pid.register() # Set metadata for DOI self.api.metadata_post(doc) # Mint DOI self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to register in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully registered in DataCite", extra=dict(pid=self.pid)) return True def update(self, url, doc): """Update metadata associated with a DOI. This can be called before/after a DOI is registered. """ if self.pid.is_deleted(): logger.info("Reactivate in DataCite", extra=dict(pid=self.pid)) try: # Set metadata self.api.metadata_post(doc) self.api.doi_post(self.pid.pid_value, url) except (DataCiteError, HttpError): logger.exception("Failed to update in DataCite", extra=dict(pid=self.pid)) raise if self.pid.is_deleted(): self.pid.sync_status(PIDStatus.REGISTERED) logger.info("Successfully updated in DataCite", extra=dict(pid=self.pid)) return True def delete(self): """Delete a registered DOI.""" try: if self.pid.is_new(): self.pid.delete() else: self.pid.delete() self.api.metadata_delete(self.pid.pid_value) except (DataCiteError, HttpError): logger.exception("Failed to delete in DataCite", extra=dict(pid=self.pid)) raise logger.info("Successfully deleted in DataCite", extra=dict(pid=self.pid)) return True def sync_status(self): """Synchronize DOI status DataCite MDS.""" status = None try: try: self.api.doi_get(self.pid.pid_value) status = PIDStatus.REGISTERED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass if status is None: try: self.api.metadata_get(self.pid.pid_value) status = PIDStatus.RESERVED except DataCiteGoneError: status = PIDStatus.DELETED except DataCiteNoContentError: status = PIDStatus.REGISTERED except DataCiteNotFoundError: pass except (DataCiteError, HttpError): logger.exception("Failed to sync status from DataCite", extra=dict(pid=self.pid)) raise if status is None: status = PIDStatus.NEW self.pid.sync_status(status) logger.info("Successfully synced status from DataCite", extra=dict(pid=self.pid)) return True
password='******', prefix='10.5072', test_mode=True ) # Set metadata for DOI d.metadata_post(doc) # Mint new DOI d.doi_post('10.5072/test-doi', 'http://example.org/test-doi') # Get DOI location location = d.doi_get("10.5072/test-doi") # Set alternate URL for content type (availble through content negotiation) d.media_post( "10.5072/test-doi", {"application/json": "http://example.org/test-doi/json/", "application/xml": "http://example.org/test-doi/xml/"} ) # Get alternate URLs mapping = d.media_get("10.5072/test-doi") assert mapping["application/json"] == "http://example.org/test-doi/json/" # Get metadata for DOI doc = d.metadata_get("10.5072/test-doi") # Make DOI inactive d.metadata_delete("10.5072/test-doi")
class DoiHelper(object): def __init__(self, conf, errors): self.conf = conf self.errors = errors self.test_mode = False #True self._create_client() def safe_call(self, f, *args): try: f(*args) except Exception as e: self.errors.append("Datacite1 connection failed") @on_no_errors def _create_client(self): datacite_kwargs = { 'username': self.conf.dc_symbol, 'password': self.conf.dc_password, 'prefix': self.conf.dc_prefix, 'test_mode': self.test_mode} #self.client = DataCiteMDSClient(**datacite_kwargs) try: self.client = DataCiteMDSClient(**datacite_kwargs) except Exception as e: self.errors.append("Datacite connection failed") @on_no_errors def find_free_doi(self): r = "".join([random.choice(string.ascii_uppercase + string.digits) for _ in range(5)]) doi = "/".join([self.conf.dc_prefix, self.conf.dc_identifier, r]) try: self.client.metadata_get(doi) return self.find_free_doi() except DataCiteServerError as e: if e.error_code != 404: self.errors.append( 'Not the expected result from MDS while validation: %s' % e) return doi @on_no_errors def _post_metadata(self, metadata): logging.debug("METADATA:" + metadata) res = self.client.metadata_post(metadata) logging.debug("RES: %s" % res) if not res.startswith("OK"): self.errors.append(res) @on_no_errors def _post_doi(self, doi, url): for testurl in [ "https://develop.osl.tib.eu", "https://test.osl.tib.eu", "https://develop.handbuch.tib.eu", "https://test.handbuch.tib.eu", "https://handbuch.tib.eu", "https://handbuch.local", ]: if testurl in url: url = url.replace(testurl, "http://handbuch.io") if "handbuch.io" in url and not self.test_mode: logging.debug("Post DOI: Doi: %s\t%s" % (doi, url)) self.client.doi_post(doi, url) def _get_creators_list(self, book): creators = [] for title in ['AUTOREN', 'HERAUSGEBER', 'KONTRIBUTOREN', ]: namesstr = book.info.get(title, "") dicts = [ {'creatorName': name.strip()} for name in namesstr.split(',') if name.strip() ] creators += [d for d in dicts if d] return creators def _get_bookdata(self, book): publisher = book.info.get('HERAUSGEBER', None) or \ book.info['AUTOREN'] data = { 'identifier': { 'identifier': book.info['doi'], 'identifierType': 'DOI', }, 'creators': self._get_creators_list(book), 'titles': [ {'title': book.book_page.friendly_title} ], 'publisher': publisher, 'publicationYear': str(datetime.now().year), 'version': str(self.conf.version) } return data def _create_doi(self, doi, url, data): metadata = None try: schema31.validate(data) metadata = schema31.tostring(data) except ValidationError as e: self.errors.append(str(e)) #import pdb; pdb.set_trace() self._post_metadata(metadata) self._post_doi(doi, url) @on_no_errors def create_chapterdoi(self, doi, url, title, book, username): #import pdb; pdb.set_trace() data = self._get_bookdata(book) data['titles'][0]['title'] = title data['identifier']['identifier'] = doi data['relatedIdentifiers'] = [{ 'relatedIdentifier': book.info['doi'], 'relatedIdentifierType': 'DOI', 'relationType':'IsPartOf'}, ] if username: data['publisher'] = username self._create_doi(doi, url, data) @on_no_errors def create_bookdoi(self, url, book): data = self._get_bookdata(book) self._create_doi(book.info['doi'], url, data)