def get_and_set_preprint_identifiers(preprint_id): from osf.models import PreprintService preprint = PreprintService.load(preprint_id) ezid_response = request_identifiers_from_ezid(preprint) id_dict = parse_identifiers(ezid_response) preprint.set_identifier_values(doi=id_dict['doi'], ark=id_dict['ark'])
def on_preprint_updated(preprint_id, update_share=True): # WARNING: Only perform Read-Only operations in an asynchronous task, until Repeatable Read/Serializable # transactions are implemented in View and Task application layers. from osf.models import PreprintService preprint = PreprintService.load(preprint_id) if preprint.node: status = 'public' if preprint.node.is_public else 'unavailable' try: update_ezid_metadata_on_change(preprint, status=status) except HTTPError as err: sentry.log_exception() sentry.log_message(err.args[0]) if settings.SHARE_URL and update_share: if not preprint.provider.access_token: raise ValueError('No access_token for {}. Unable to send {} to SHARE.'.format(preprint.provider, preprint)) resp = requests.post('{}api/v2/normalizeddata/'.format(settings.SHARE_URL), json={ 'data': { 'type': 'NormalizedData', 'attributes': { 'tasks': [], 'raw': None, 'data': {'@graph': format_preprint(preprint)} } } }, headers={'Authorization': 'Bearer {}'.format(preprint.provider.access_token), 'Content-Type': 'application/vnd.api+json'}) logger.debug(resp.content) resp.raise_for_status()
def on_preprint_updated(preprint_id): # WARNING: Only perform Read-Only operations in an asynchronous task, until Repeatable Read/Serializable # transactions are implemented in View and Task application layers. from osf.models import PreprintService preprint = PreprintService.load(preprint_id) if settings.SHARE_URL: if not preprint.provider.access_token: raise ValueError( 'No access_token for {}. Unable to send {} to SHARE.'.format( preprint.provider, preprint)) resp = requests.post( '{}api/v2/normalizeddata/'.format(settings.SHARE_URL), json={ 'data': { 'type': 'NormalizedData', 'attributes': { 'tasks': [], 'raw': None, 'data': { '@graph': format_preprint(preprint) } } } }, headers={ 'Authorization': 'Bearer {}'.format(preprint.provider.access_token), 'Content-Type': 'application/vnd.api+json' }) logger.debug(resp.content) resp.raise_for_status()
def _async_update_preprint_share(self, preprint_id, old_subjects, share_type): # Any modifications to this function may need to change _update_preprint_share # Takes preprint_id to ensure async retries push fresh data PreprintService = apps.get_model('osf.PreprintService') preprint = PreprintService.load(preprint_id) data = serialize_share_preprint_data(preprint, share_type, old_subjects) resp = send_share_preprint_data(preprint, data) try: resp = requests.post('{}api/v2/normalizeddata/'.format(settings.SHARE_URL), json={ 'data': { 'type': 'NormalizedData', 'attributes': { 'tasks': [], 'raw': None, 'data': {'@graph': format_preprint(preprint, share_type, old_subjects)} } } }, headers={'Authorization': 'Bearer {}'.format(preprint.provider.access_token), 'Content-Type': 'application/vnd.api+json'}) logger.debug(resp.content) resp.raise_for_status() except Exception as e: if resp.status_code >= 500: if self.request.retries == self.max_retries: send_desk_share_preprint_error(preprint, resp, self.request.retries) raise self.retry( exc=e, countdown=(random.random() + 1) * min(60 + settings.CELERY_RETRY_BACKOFF_BASE ** self.request.retries, 60 * 10) ) else: send_desk_share_preprint_error(preprint, resp, self.request.retries)
def get_and_set_preprint_identifiers(preprint_id): PreprintService = apps.get_model('osf.PreprintService') preprint = PreprintService.load(preprint_id) ezid_response = request_identifiers_from_ezid(preprint) if ezid_response is None: return id_dict = parse_identifiers(ezid_response) preprint.set_identifier_values(doi=id_dict['doi'], save=True)
def get_and_set_preprint_identifiers(preprint_id): PreprintService = apps.get_model('osf.PreprintService') preprint = PreprintService.load(preprint_id) ezid_response = request_identifiers_from_ezid(preprint) if ezid_response is None: return id_dict = parse_identifiers(ezid_response) preprint.set_identifier_values(doi=id_dict['doi'], ark=id_dict['ark'], save=True)
def get_preprint_provider(self, obj): preprint_id = obj.get('preprint', None) if preprint_id: preprint = PreprintService.load(preprint_id) if preprint: provider = preprint.provider return {'url': provider.external_url, 'name': provider.name} return None
def post(self, request): crossref_email_content = lxml.etree.fromstring(str(request.POST['body-plain'])) status = crossref_email_content.get('status').lower() # from element doi_batch_diagnostic record_count = int(crossref_email_content.find('batch_data/record_count').text) records = crossref_email_content.xpath('//record_diagnostic') dois_processed = 0 if status == 'completed': guids = [] # Keep track of errors recieved, ignore those that are handled unexpected_errors = False for record in records: doi = getattr(record.find('doi'), 'text', None) guid = doi.split('/')[-1] if doi else None guids.append(guid) preprint = PreprintService.load(guid) if guid else None if record.get('status').lower() == 'success' and doi: msg = record.find('msg').text created = bool(msg == 'Successfully added') legacy_doi = preprint.get_identifier(category='legacy_doi') if created or legacy_doi: # Sets preprint_doi_created and saves the preprint preprint.set_identifier_values(doi=doi, save=True) # Double records returned when possible matching DOI is found in crossref elif 'possible preprint/vor pair' not in msg.lower(): # Directly updates the identifier preprint.set_identifier_value(category='doi', value=doi) dois_processed += 1 # Mark legacy DOIs overwritten by newly batch confirmed crossref DOIs if legacy_doi: legacy_doi.remove() elif record.get('status').lower() == 'failure': if 'Relation target DOI does not exist' in record.find('msg').text: logger.warn('Related publication DOI does not exist, sending metadata again without it...') client = preprint.get_doi_client() client.create_identifier(preprint, category='doi', include_relation=False) # This error occurs when a single preprint is being updated several times in a row with the same metadata [#PLAT-944] elif 'less or equal to previously submitted version' in record.find('msg').text and record_count == 2: break else: unexpected_errors = True logger.info('Creation success email received from CrossRef for preprints: {}'.format(guids)) if dois_processed != record_count or status != 'completed': if unexpected_errors: batch_id = crossref_email_content.find('batch_id').text mails.send_mail( to_addr=settings.OSF_SUPPORT_EMAIL, mail=mails.CROSSREF_ERROR, batch_id=batch_id, email_content=request.POST['body-plain'], ) logger.error('Error submitting metadata for batch_id {} with CrossRef, email sent to help desk'.format(batch_id)) return HttpResponse('Mail received', status=200)
def on_preprint_updated(preprint_id, update_share=True, share_type=None, old_subjects=None, saved_fields=None): # WARNING: Only perform Read-Only operations in an asynchronous task, until Repeatable Read/Serializable # transactions are implemented in View and Task application layers. from osf.models import PreprintService preprint = PreprintService.load(preprint_id) if old_subjects is None: old_subjects = [] if should_update_preprint_identifiers(preprint, old_subjects, saved_fields): update_or_create_preprint_identifiers(preprint) if update_share: update_preprint_share(preprint, old_subjects, share_type)
def on_preprint_updated(preprint_id, update_share=True, share_type=None, old_subjects=None): # WARNING: Only perform Read-Only operations in an asynchronous task, until Repeatable Read/Serializable # transactions are implemented in View and Task application layers. from osf.models import PreprintService preprint = PreprintService.load(preprint_id) if old_subjects is None: old_subjects = [] if preprint.node: update_or_create_preprint_identifiers(preprint) if update_share: update_preprint_share(preprint, old_subjects, share_type)
def on_preprint_updated(preprint_id, update_share=True, share_type=None, old_subjects=None): # WARNING: Only perform Read-Only operations in an asynchronous task, until Repeatable Read/Serializable # transactions are implemented in View and Task application layers. from osf.models import PreprintService preprint = PreprintService.load(preprint_id) if old_subjects is None: old_subjects = [] if preprint.node: status = 'public' if preprint.verified_publishable else 'unavailable' try: update_ezid_metadata_on_change(preprint._id, status=status) except HTTPError as err: sentry.log_exception() sentry.log_message(err.args[0]) if update_share: update_preprint_share(preprint, old_subjects, share_type)
def test_create_preprint_adds_log_if_published(self, mock_get_identifiers): public_project_payload = build_preprint_create_payload( self.public_project._id, self.provider._id, self.file_one_public_project._id, { 'is_published': True, 'subjects': [[SubjectFactory()._id]], }) res = self.app.post_json_api(self.url, public_project_payload, auth=self.user.auth) assert_equal(res.status_code, 201) preprint_id = res.json['data']['id'] preprint = PreprintService.load(preprint_id) log = preprint.node.logs.latest() assert_equal(log.action, 'preprint_initiated') assert_equal(log.params.get('preprint'), preprint_id)
def test_create_preprint_adds_log_if_published(self): public_project_payload = build_preprint_create_payload( self.public_project._id, self.provider._id, self.file_one_public_project._id, { 'is_published': True, 'subjects': [[SubjectFactory()._id]], } ) res = self.app.post_json_api(self.url, public_project_payload, auth=self.user.auth) assert_equal(res.status_code, 201) preprint_id = res.json['data']['id'] preprint = PreprintService.load(preprint_id) log = preprint.node.logs.latest() assert_equal(log.action, 'preprint_initiated') assert_equal(log.params.get('preprint'), preprint_id)
def _async_update_preprint_share(self, preprint_id, old_subjects, share_type): # Any modifications to this function may need to change _update_preprint_share # Takes preprint_id to ensure async retries push fresh data PreprintService = apps.get_model('osf.PreprintService') preprint = PreprintService.load(preprint_id) data = serialize_share_preprint_data(preprint, share_type, old_subjects) resp = send_share_preprint_data(preprint, data) try: resp.raise_for_status() except Exception as e: if resp.status_code >= 500: if self.request.retries == self.max_retries: send_desk_share_preprint_error(preprint, resp, self.request.retries) raise self.retry( exc=e, countdown=(random.random() + 1) * min(60 + settings.CELERY_RETRY_BACKOFF_BASE ** self.request.retries, 60 * 10) ) else: send_desk_share_preprint_error(preprint, resp, self.request.retries)
def _async_update_preprint_share(self, preprint_id, old_subjects, share_type): # Any modifications to this function may need to change _update_preprint_share # Takes preprint_id to ensure async retries push fresh data PreprintService = apps.get_model('osf.PreprintService') preprint = PreprintService.load(preprint_id) data = serialize_share_preprint_data(preprint, share_type, old_subjects) resp = send_share_preprint_data(preprint, data) try: resp.raise_for_status() except Exception as e: if resp.status_code >= 500: if self.request.retries == self.max_retries: send_desk_share_preprint_error(preprint, resp, self.request.retries) raise self.retry(exc=e, countdown=(random.random() + 1) * min( 60 + settings.CELERY_RETRY_BACKOFF_BASE** self.request.retries, 60 * 10)) else: send_desk_share_preprint_error(preprint, resp, self.request.retries)