def get_or_create_assertion(cls, url=None, imagefile=None, assertion=None, created_by=None): # distill 3 optional arguments into one query argument query = (url, imagefile, assertion) query = filter(lambda v: v is not None, query) if len(query) != 1: raise ValueError("Must provide only 1 of: url, imagefile or assertion_obo") query = query[0] if created_by: badgecheck_recipient_profile = { 'email': created_by.all_recipient_identifiers } else: badgecheck_recipient_profile = None try: response = openbadges.verify(query, recipient_profile=badgecheck_recipient_profile, **cls.badgecheck_options()) except ValueError as e: raise ValidationError([{'name': "INVALID_BADGE", 'description': str(e)}]) report = response.get('report', {}) is_valid = report.get('valid') if not is_valid: if report.get('errorCount', 0) > 0: errors = list(cls.translate_errors(report.get('messages', []))) else: errors = [{'name': "UNABLE_TO_VERIFY", 'description': "Unable to verify the assertion"}] raise ValidationError(errors) graph = response.get('graph', []) assertion_obo = first_node_match(graph, dict(type="Assertion")) if not assertion_obo: raise ValidationError([{'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an assertion"}]) badgeclass_obo = first_node_match(graph, dict(id=assertion_obo.get('badge', None))) if not badgeclass_obo: raise ValidationError([{'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find a badgeclass"}]) issuer_obo = first_node_match(graph, dict(id=badgeclass_obo.get('issuer', None))) if not issuer_obo: raise ValidationError([{'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an issuer"}]) original_json = response.get('input').get('original_json', {}) recipient_identifier = report.get('recipientProfile', {}).get('email', None) with transaction.atomic(): issuer, issuer_created = Issuer.objects.get_or_create_from_ob2(issuer_obo, original_json=original_json.get(issuer_obo.get('id'))) badgeclass, badgeclass_created = BadgeClass.objects.get_or_create_from_ob2(issuer, badgeclass_obo, original_json=original_json.get(badgeclass_obo.get('id'))) return BadgeInstance.objects.get_or_create_from_ob2(badgeclass, assertion_obo, recipient_identifier=recipient_identifier, original_json=original_json.get(assertion_obo.get('id')))
def test_submit_basic_1_0_badge_missing_badge_prop(self): self.setup_user(email='*****@*****.**', authenticate=True) responses.add( responses.GET, 'http://a.com/instance', body=open(os.path.join(dir, 'testfiles/1_0_basic_instance_missing_badge_prop.json')).read(), status=200, content_type='application/json' ) setup_resources([ {'url': OPENBADGES_CONTEXT_V1_URI, 'filename': 'v1_context.json'}, {'url': OPENBADGES_CONTEXT_V2_URI, 'response_body': json.dumps(OPENBADGES_CONTEXT_V2_DICT)} ]) post_input = { 'url': 'http://a.com/instance' } response = self.client.post( '/v1/earner/badges', post_input ) self.assertEqual(response.status_code, 400) self.assertIsNotNone(first_node_match(response.data, dict( messageLevel='ERROR', name='VALIDATE_PROPERTY', prop_name='badge' )))
def get_assertion_obo(cls, badge_instance): try: response = openbadges.verify(badge_instance.source_url, recipient_profile=None, **cls.badgecheck_options()) except ValueError as e: return None report = response.get('report', {}) is_valid = report.get('valid') if is_valid: graph = response.get('graph', []) assertion_obo = first_node_match(graph, dict(type="Assertion")) if assertion_obo: return assertion_obo
def test_submit_basic_1_0_badge_missing_issuer(self): setup_basic_1_0(**{'exclude': ['http://a.com/issuer']}) setup_resources([ {'url': OPENBADGES_CONTEXT_V1_URI, 'filename': 'v1_context.json'}, {'url': OPENBADGES_CONTEXT_V2_URI, 'response_body': json.dumps(OPENBADGES_CONTEXT_V2_DICT)} ]) self.setup_user(email='*****@*****.**', authenticate=True) post_input = { 'url': 'http://a.com/instance' } response = self.client.post( '/v1/earner/badges', post_input ) self.assertEqual(response.status_code, 400) self.assertIsNotNone(first_node_match(response.data, dict( messageLevel='ERROR', name='FETCH_HTTP_NODE' )))
def test_submit_basic_1_0_badge_via_url_bad_email(self): setup_basic_1_0() setup_resources([ {'url': OPENBADGES_CONTEXT_V1_URI, 'filename': 'v1_context.json'}, {'url': OPENBADGES_CONTEXT_V2_URI, 'response_body': json.dumps(OPENBADGES_CONTEXT_V2_DICT)} ]) self.setup_user(email='*****@*****.**', authenticate=True) post_input = { 'url': 'http://a.com/instance' } response = self.client.post( '/v1/earner/badges', post_input ) self.assertEqual(response.status_code, 400) self.assertIsNotNone(first_node_match(response.data, dict( messageLevel='ERROR', name='VERIFY_RECIPIENT_IDENTIFIER', )))
def test_submit_badge_assertion_with_bad_date(self): setup_basic_1_0() setup_resources([ {'url': 'http://a.com/instancebaddate', 'filename': '1_0_basic_instance_with_bad_date.json'}, {'url': OPENBADGES_CONTEXT_V1_URI, 'filename': 'v1_context.json'}, {'url': OPENBADGES_CONTEXT_V2_URI, 'response_body': json.dumps(OPENBADGES_CONTEXT_V2_DICT)} ]) self.setup_user(email='*****@*****.**', authenticate=True) post_input = { 'url': 'http://a.com/instancebaddate' } response = self.client.post( '/v1/earner/badges', post_input ) self.assertEqual(response.status_code, 400) self.assertIsNotNone(first_node_match(response.data, dict( messageLevel='ERROR', name='VALIDATE_PROPERTY', prop_name='issuedOn' )))
def post(self, request, **kwargs): entity_id = request.data.get('entity_id') badge_instance = self.get_object(entity_id) #only do badgecheck verify if not a local badge if (badge_instance.source_url): recipient_profile = { badge_instance.recipient_type: badge_instance.recipient_identifier } badge_check_options = { 'include_original_json': True, 'use_cache': True, } try: response = openbadges.verify(badge_instance.jsonld_id, recipient_profile=recipient_profile, **badge_check_options) except ValueError as e: raise ValidationError([{'name': "INVALID_BADGE", 'description': str(e)}]) graph = response.get('graph', []) revoked_obo = first_node_match(graph, dict(revoked=True)) if bool(revoked_obo): instance = BadgeInstance.objects.get(source_url=revoked_obo['id']) instance.revoke(revoked_obo.get('revocationReason', 'Badge is revoked')) else: report = response.get('report', {}) is_valid = report.get('valid') if not is_valid: if report.get('errorCount', 0) > 0: errors = [{'name': 'UNABLE_TO_VERIFY', 'description': 'Unable to verify the assertion'}] raise ValidationError(errors) validation_subject = report.get('validationSubject') badge_instance_obo = first_node_match(graph, dict(id=validation_subject)) if not badge_instance_obo: raise ValidationError([{'name': 'ASSERTION_NOT_FOUND', 'description': 'Unable to find an badge instance'}]) badgeclass_obo = first_node_match(graph, dict(id=badge_instance_obo.get('badge', None))) if not badgeclass_obo: raise ValidationError([{'name': 'ASSERTION_NOT_FOUND', 'description': 'Unable to find a badgeclass'}]) issuer_obo = first_node_match(graph, dict(id=badgeclass_obo.get('issuer', None))) if not issuer_obo: raise ValidationError([{'name': 'ASSERTION_NOT_FOUND', 'description': 'Unable to find an issuer'}]) original_json = response.get('input').get('original_json', {}) BadgeInstance.objects.update_from_ob2( badge_instance.badgeclass, badge_instance_obo, badge_instance.recipient_identifier, badge_instance.recipient_type, original_json.get(badge_instance_obo.get('id', ''), None) ) badge_instance.rebake(save=True) BadgeClass.objects.update_from_ob2( badge_instance.issuer, badgeclass_obo, original_json.get(badgeclass_obo.get('id', ''), None) ) Issuer.objects.update_from_ob2( issuer_obo, original_json.get(issuer_obo.get('id', ''), None) ) result = self.get_object(entity_id).get_json(expand_badgeclass=True, expand_issuer=True) return Response(BaseSerializerV2.response_envelope([result], True, 'OK'), status=status.HTTP_200_OK)
def get_or_create_assertion(cls, url=None, imagefile=None, assertion=None, created_by=None): # distill 3 optional arguments into one query argument query = (url, imagefile, assertion) query = filter(lambda v: v is not None, query) if len(query) != 1: raise ValueError( "Must provide only 1 of: url, imagefile or assertion_obo") query = query[0] if created_by: emails = [d.email for d in created_by.email_items.all()] badgecheck_recipient_profile = { 'email': emails + [v.email for v in created_by.cached_email_variants()], 'telephone': created_by.cached_verified_phone_numbers(), 'url': created_by.cached_verified_urls() } else: badgecheck_recipient_profile = None try: if type(query) is dict: try: query = json.dumps(query) except (TypeError, ValueError): raise ValidationError("Could not parse dict to json") response = openbadges.verify( query, recipient_profile=badgecheck_recipient_profile, **cls.badgecheck_options()) except ValueError as e: raise ValidationError([{ 'name': "INVALID_BADGE", 'description': str(e) }]) report = response.get('report', {}) is_valid = report.get('valid') if not is_valid: if report.get('errorCount', 0) > 0: errors = list(cls.translate_errors(report.get('messages', []))) else: errors = [{ 'name': "UNABLE_TO_VERIFY", 'description': "Unable to verify the assertion" }] raise ValidationError(errors) graph = response.get('graph', []) assertion_obo = first_node_match(graph, dict(type="Assertion")) if not assertion_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an assertion" }]) badgeclass_obo = first_node_match( graph, dict(id=assertion_obo.get('badge', None))) if not badgeclass_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find a badgeclass" }]) issuer_obo = first_node_match( graph, dict(id=badgeclass_obo.get('issuer', None))) if not issuer_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an issuer" }]) original_json = response.get('input').get('original_json', {}) recipient_profile = report.get('recipientProfile', {}) recipient_type, recipient_identifier = recipient_profile.items()[0] def commit_new_badge(): with transaction.atomic(): issuer, issuer_created = Issuer.objects.get_or_create_from_ob2( issuer_obo, original_json=original_json.get(issuer_obo.get('id'))) badgeclass, badgeclass_created = BadgeClass.objects.get_or_create_from_ob2( issuer, badgeclass_obo, original_json=original_json.get(badgeclass_obo.get('id'))) if badgeclass_created and (getattr( settings, 'BADGERANK_NOTIFY_ON_BADGECLASS_CREATE', True) or getattr( settings, 'BADGERANK_NOTIFY_ON_FIRST_ASSERTION', True)): from issuer.tasks import notify_badgerank_of_badgeclass notify_badgerank_of_badgeclass.delay( badgeclass_pk=badgeclass.pk) return BadgeInstance.objects.get_or_create_from_ob2( badgeclass, assertion_obo, recipient_identifier=recipient_identifier, recipient_type=recipient_type, original_json=original_json.get(assertion_obo.get('id'))) try: return commit_new_badge() except IntegrityError: logger.error( "Race condition caught when saving new assertion: {}".format( query)) return commit_new_badge()
def get_or_create_assertion(cls, url=None, imagefile=None, assertion=None, created_by=None): # distill 3 optional arguments into one query argument query = (url, imagefile, assertion) query = filter(lambda v: v is not None, query) if len(query) != 1: raise ValueError( "Must provide only 1 of: url, imagefile or assertion_obo") query = query[0] if created_by: recipient_id = created_by.get_recipient_identifier(), badgecheck_recipient_profile = { 'id': created_by.get_recipient_identifier(), 'email': [email.email for email in created_by.verified_emails] } else: badgecheck_recipient_profile = None try: response = openbadges.verify( query, recipient_profile=badgecheck_recipient_profile, **cls.badgecheck_options()) except ValueError as e: raise ValidationError([{ 'name': "INVALID_BADGE", 'description': str(e) }]) report = response.get('report', {}) # override VALIDATE_PROPERTY for id, until IMS accepts EduID iri format if report['errorCount'] > 0: index_of_uri_format_failure = None uri_format_message_found = False for index, message in enumerate(report['messages']): if 'not valid in unknown type node' in message['result']: index_of_uri_format_failure = index uri_format_message_found = True if uri_format_message_found: report['errorCount'] -= 1 report['messages'].pop(index_of_uri_format_failure) if report['errorCount'] == 0: report['valid'] = True is_valid = report.get('valid') if not is_valid: if report.get('errorCount', 0) > 0: errors = list(cls.translate_errors(report.get('messages', []))) else: errors = [{ 'name': "UNABLE_TO_VERIFY", 'description': "Unable to verify the assertion" }] raise ValidationError(errors) graph = response.get('graph', []) assertion_obo = first_node_match(graph, dict(type="Assertion")) if not assertion_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an assertion" }]) badgeclass_obo = first_node_match( graph, dict(id=assertion_obo.get('badge', None))) if not badgeclass_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find a badgeclass" }]) issuer_obo = first_node_match( graph, dict(id=badgeclass_obo.get('issuer', None))) if not issuer_obo: raise ValidationError([{ 'name': "ASSERTION_NOT_FOUND", 'description': "Unable to find an issuer" }]) original_json = response.get('input').get('original_json', {}) recipient_identifier = report.get('recipientProfile', {}).get( 'id', None) # first use 'id' as the recipient_identifier type if not recipient_identifier: # the assertion might instead have the 'email' recipient_identifier type recipient_identifier = report.get('recipientProfile', {}).get('email', None) with transaction.atomic(): issuer, issuer_created = Issuer.objects.get_or_create_from_ob2( issuer_obo, original_json=original_json.get(issuer_obo.get('id'))) badgeclass, badgeclass_created = BadgeClass.objects.get_or_create_from_ob2( issuer, badgeclass_obo, original_json=original_json.get(badgeclass_obo.get('id'))) return BadgeInstance.objects.get_or_create_from_ob2( badgeclass, assertion_obo, recipient_identifier=recipient_identifier, original_json=original_json.get(assertion_obo.get('id')))