Example #1
0
    def save(self, *args, **kwargs):
        if self.pk is None:
            self.salt = uuid.uuid4().hex
            self.created_at = datetime.datetime.now()

            # do this now instead of in AbstractVersionedEntity.save() so we can use it for image name
            if self.entity_id is None:
                self.entity_id = generate_entity_uri()

            if not self.image:
                badgeclass_name, ext = os.path.splitext(self.badgeclass.image.file.name)
                new_image = StringIO.StringIO()
                bake(image_file=self.cached_badgeclass.image.file,
                     assertion_json_string=json_dumps(self.get_json(obi_version=UNVERSIONED_BAKED_VERSION), indent=2),
                     output_file=new_image)
                self.image.save(name='assertion-{id}{ext}'.format(id=self.entity_id, ext=ext),
                                content=ContentFile(new_image.read()),
                                save=False)

            try:
                from badgeuser.models import CachedEmailAddress
                existing_email = CachedEmailAddress.cached.get(email=self.recipient_identifier)
                if self.recipient_identifier != existing_email.email and \
                        self.recipient_identifier not in [e.email for e in existing_email.cached_variants()]:
                    existing_email.add_variant(self.recipient_identifier)
            except CachedEmailAddress.DoesNotExist:
                pass

        if self.revoked is False:
            self.revocation_reason = None

        super(BadgeInstance, self).save(*args, **kwargs)
Example #2
0
    def save(self, *args, **kwargs):
        if self.pk is None:
            self.salt = uuid.uuid4().hex
            self.created_at = datetime.datetime.now()

            # do this now instead of in AbstractVersionedEntity.save() so we can use it for image name
            if self.entity_id is None:
                self.entity_id = generate_entity_uri()

            if not self.image:
                badgeclass_name, ext = os.path.splitext(self.badgeclass.image.file.name)
                new_image = StringIO.StringIO()
                bake(image_file=self.cached_badgeclass.image.file,
                     assertion_json_string=json_dumps(self.get_json(obi_version=UNVERSIONED_BAKED_VERSION), indent=2),
                     output_file=new_image)
                self.image.save(name='assertion-{id}{ext}'.format(id=self.entity_id, ext=ext),
                                content=ContentFile(new_image.read()),
                                save=False)

            try:
                from badgeuser.models import CachedEmailAddress
                existing_email = CachedEmailAddress.cached.get(email=self.recipient_identifier)
                if self.recipient_identifier != existing_email.email and \
                        self.recipient_identifier not in [e.email for e in existing_email.cached_variants()]:
                    existing_email.add_variant(self.recipient_identifier)
            except CachedEmailAddress.DoesNotExist:
                pass

        if self.revoked is False:
            self.revocation_reason = None

        super(BadgeInstance, self).save(*args, **kwargs)
Example #3
0
    def get_baked_image_url(self, obi_version=CURRENT_OBI_VERSION):
        if obi_version == UNVERSIONED_BAKED_VERSION:
            # requested version is the one referenced in assertion.image
            return self.image.url

        try:
            baked_image = BadgeInstanceBakedImage.cached.get(badgeinstance=self, obi_version=obi_version)
        except BadgeInstanceBakedImage.DoesNotExist:
            # rebake
            baked_image = BadgeInstanceBakedImage(badgeinstance=self, obi_version=obi_version)

            json_to_bake = self.get_json(
                obi_version=obi_version,
                expand_issuer=True,
                expand_badgeclass=True,
                include_extra=True
            )
            badgeclass_name, ext = os.path.splitext(self.badgeclass.image.file.name)
            new_image = StringIO.StringIO()
            bake(image_file=self.cached_badgeclass.image.file,
                 assertion_json_string=json_dumps(json_to_bake, indent=2),
                 output_file=new_image)
            baked_image.image.save(
                name='assertion-{id}-{version}{ext}'.format(id=self.entity_id, ext=ext, version=obi_version),
                content=ContentFile(new_image.read()),
                save=False
            )
            baked_image.save()

        return baked_image.image.url
Example #4
0
    def get_baked_image_url(self, obi_version=CURRENT_OBI_VERSION):
        if obi_version == UNVERSIONED_BAKED_VERSION:
            # requested version is the one referenced in assertion.image
            return self.image.url

        try:
            baked_image = BadgeInstanceBakedImage.cached.get(
                badgeinstance=self, obi_version=obi_version)
        except BadgeInstanceBakedImage.DoesNotExist:
            # rebake
            baked_image = BadgeInstanceBakedImage(badgeinstance=self,
                                                  obi_version=obi_version)

            json_to_bake = self.get_json(obi_version=obi_version,
                                         expand_issuer=True,
                                         expand_badgeclass=True,
                                         include_extra=True)
            badgeclass_name, ext = os.path.splitext(
                self.badgeclass.image.file.name)
            new_image = StringIO.StringIO()
            bake(image_file=self.cached_badgeclass.image.file,
                 assertion_json_string=json_dumps(json_to_bake, indent=2),
                 output_file=new_image)
            baked_image.image.save(name='assertion-{id}-{version}{ext}'.format(
                id=self.entity_id, ext=ext, version=obi_version),
                                   content=ContentFile(new_image.read()),
                                   save=False)
            baked_image.save()

        return baked_image.image.url
Example #5
0
    def rebake(self, obi_version=CURRENT_OBI_VERSION, save=True):
        if self.source_url:
            # dont rebake imported assertions
            return

        new_image = StringIO.StringIO()
        bake(
            image_file=self.cached_badgeclass.image.file,
            assertion_json_string=json_dumps(self.get_json(obi_version=obi_version), indent=2),
            output_file=new_image
        )
        new_name = default_storage.save(self.image.name, ContentFile(new_image.read()))
        self.image.name = new_name
        if save:
            self.save()
Example #6
0
    def rebake(self, obi_version=CURRENT_OBI_VERSION, save=True):
        if self.source_url:
            # dont rebake imported assertions
            return

        new_image = StringIO.StringIO()
        bake(image_file=self.cached_badgeclass.image.file,
             assertion_json_string=json_dumps(
                 self.get_json(obi_version=obi_version), indent=2),
             output_file=new_image)
        new_name = default_storage.save(self.image.name,
                                        ContentFile(new_image.read()))
        self.image.name = new_name
        if save:
            self.save()
 def test_subject_set_from_badge_image(self):
     with open(os.path.join(os.path.dirname(__file__), 'testfiles', 'public_domain_heart.png'), 'rb') as f:
         image = bake(f, test_components['2_0_basic_assertion'])
         self.set_response_mocks()
         store = verification_store(image)
         report = generate_report(store)
         self.assertEqual(report['report']['validationSubject'], 'https://example.org/beths-robotics-badge.json')
Example #8
0
 def bakery(self, award: Award):
     assertion = self.openbadges.badge_assertion(award)
     image = self.badge_service.open_image(award)
     image = openbadges_bakery.bake(image, json.dumps(assertion))
     image.seek(0)
     image_bytes = BytesIO(image.read())
     return BadgeImage(data=image_bytes, path=None)
Example #9
0
def bake_badge_instance(badge_instance, badge_class_image_url):
    try:
        unbaked_image = ContentFile(
            requests.get(badge_class_image_url)._content, "unbaked_image.png")
        unbaked_image.open()
        baked_image = bake(unbaked_image, json.dumps(badge_instance, indent=2))
    except requests.exceptions.RequestException as e:
        raise ValidationError("Error retrieving image {}: {}".format(
            badge_class_image_url, e.message))
    return baked_image
Example #10
0
def bake_badge_instance(badge_instance, badge_class_image_url):
    try:
        unbaked_image = ContentFile(
            requests.get(badge_class_image_url)._content, "unbaked_image.png")
        unbaked_image.open()
        baked_image = bake(unbaked_image, json.dumps(badge_instance, indent=2))
    except requests.exceptions.RequestException as e:
        raise ValidationError(
            "Error retrieving image {}: {}".format(
                badge_class_image_url, e.message))
    return baked_image
Example #11
0
    def test_verify_of_baked_image(self):
        url = 'https://example.org/beths-robotics-badge.json'
        png_badge = os.path.join(os.path.dirname(__file__), 'testfiles',
                                 'public_domain_heart.png')
        responses.add(responses.GET,
                      url,
                      body=test_components['2_0_basic_assertion'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')
        responses.add(responses.GET,
                      'https://w3id.org/openbadges/v2',
                      body=test_components['openbadges_context'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/robotics-badge.json',
                      body=test_components['2_0_basic_badgeclass'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/robotics-badge.png')
        responses.add(responses.GET,
                      'https://example.org/organization.json',
                      body=test_components['2_0_basic_issuer'],
                      status=200,
                      content_type='application/ld+json')

        with open(png_badge, 'rb') as image:
            baked_image = bake(image, test_components['2_0_basic_assertion'])
            responses.add(responses.GET,
                          'https://example.org/baked',
                          body=baked_image.read(),
                          content_type='image/png')
            results = verify(baked_image)

        # verify gets the JSON out of the baked image, and then detect_input_type
        # will reach out to the assertion URL to fetch the canonical assertion (thus,
        # we expect this to become an URL input type for the verifier).
        self.assertNotEqual(results, None)
        self.assertEqual(results.get('input').get('value'), url)
        self.assertEqual(results.get('input').get('input_type'), 'url')
        self.assertEqual(len(results['report']['messages']), 0,
                         "There should be no failing tasks.")

        # Verify that the same result occurs when passing in the baked image url.
        another_result = verify('https://example.org/baked')
        self.assertTrue(another_result['report']['valid'])
        self.assertEqual(another_result['report']['validationSubject'],
                         results['report']['validationSubject'])
Example #12
0
    def save(self, *args, **kwargs):
        if self.pk is None:
            self.json['recipient']['salt'] = salt = self.get_new_slug()
            self.json['recipient']['identity'] = \
                generate_sha256_hashstring(self.recipient_identifier, salt)

            self.created_at = datetime.datetime.now()
            self.json['issuedOn'] = self.created_at.isoformat()

            imageFile = default_storage.open(self.badgeclass.image)
            self.image = bake(imageFile, json.dumps(self.json, indent=2))

            self.image.open()

        if self.revoked is False:
            self.revocation_reason = None

        # TODO: If we don't want AutoSlugField to ensure uniqueness, configure it
        super(BadgeInstance, self).save(*args, **kwargs)
Example #13
0
    def save(self, *args, **kwargs):
        if self.pk is None:
            self.json['recipient']['salt'] = salt = self.get_new_slug()
            self.json['recipient']['identity'] = \
                generate_sha256_hashstring(self.recipient_identifier, salt)

            self.created_at = datetime.datetime.now()
            self.json['issuedOn'] = self.created_at.isoformat()

            imageFile = default_storage.open(self.badgeclass.image.file.name)
            self.image = bake(imageFile, json.dumps(self.json, indent=2))

            self.image.open()

        if self.revoked is False:
            self.revocation_reason = None

        # TODO: If we don't want AutoSlugField to ensure uniqueness, configure it
        super(BadgeInstance, self).save(*args, **kwargs)
Example #14
0
    def test_fetch_task_handles_potential_baked_input(self):
        set_up_context_mock()
        assertion_url = 'http://example.org/assertion/1'
        image_url = 'http://example.org/image'

        with open(
                os.path.join(os.path.dirname(__file__), 'testfiles',
                             'public_domain_heart.png'), 'rb') as f:
            baked_file = bake(f, assertion_url)

        responses.add(responses.GET,
                      image_url,
                      body=baked_file.read(),
                      status=200,
                      content_type='image/png')

        task = add_task(FETCH_HTTP_NODE,
                        url=image_url,
                        is_potential_baked_input=True)
        result, message, actions = run_task({}, task)

        self.assertTrue(result)
        store_resource_action = [
            a for a in actions if a.get('type') == STORE_ORIGINAL_RESOURCE
        ][0]
        process_baked_input_action = [
            a for a in actions if a.get('name') == PROCESS_BAKED_RESOURCE
        ][0]

        self.assertEqual(store_resource_action.get('node_id'), image_url)
        self.assertEqual(process_baked_input_action.get('node_id'), image_url)

        task = add_task(FETCH_HTTP_NODE,
                        url=image_url,
                        is_potential_baked_input=False)
        result, message, actions = run_task({}, task)
        self.assertTrue(result)
Example #15
0
    def test_submit_baked_1_1_badge_preserves_metadata_roundtrip(self):
        assertion_metadata = {
            "@context": "https://w3id.org/openbadges/v1",
            "type": "Assertion",
            "id": "http://a.com/instance2",
            "recipient": {"identity": "*****@*****.**", "hashed": False, "type": "email"},
            "badge": "http://a.com/badgeclass",
            "issuedOn": "2015-04-30T00:00+00:00",
            "verify": {"type": "hosted", "url": "http://a.com/instance2"},
            "extensions:ExampleExtension": {
                "@context": "https://openbadgespec.org/extensions/exampleExtension/context.json",
                "type": ["Extension", "extensions:ExampleExtension"],
                "exampleProperty": "some extended text"
            },
            "schema:unknownMetadata": 55
        }
        badgeclass_metadata = {
            "@context": "https://w3id.org/openbadges/v1",
            "type": "BadgeClass",
            "id": "http://a.com/badgeclass",
            "name": "Basic Badge",
            "description": "Basic as it gets. v1.1",
            "image": "http://a.com/badgeclass_image",
            "criteria": "http://a.com/badgeclass_criteria",
            "issuer": "http://a.com/issuer"
        }
        issuer_metadata = {
            "@context": "https://w3id.org/openbadges/v1",
            "type": "Issuer",
            "id": "http://a.com/issuer",
            "name": "Basic Issuer",
            "url": "http://a.com/issuer/website"
        }

        with open(os.path.join(dir, 'testfiles/baked_image.png')) as image_file:
            original_image = bake(image_file, json.dumps(assertion_metadata))
            original_image.seek(0)

        responses.add(
            responses.GET, 'http://a.com/badgeclass_image',
            body=open(os.path.join(dir, 'testfiles/unbaked_image.png')).read(),
            status=200, content_type='image/png'
        )

        setup_resources([
            {'url': OPENBADGES_CONTEXT_V1_URI, 'filename': 'v1_context.json'},
            {'url': OPENBADGES_CONTEXT_V2_URI, 'response_body': json.dumps(OPENBADGES_CONTEXT_V2_DICT)},
            {'url': "https://openbadgespec.org/extensions/exampleExtension/context.json", 'response_body': json.dumps(
                {
                    "@context": {
                        "obi": "https://w3id.org/openbadges#",
                        "extensions": "https://w3id.org/openbadges/extensions#",
                        "exampleProperty": "http://schema.org/text"
                    },
                    "obi:validation": [
                        {
                            "obi:validatesType": "extensions:ExampleExtension",
                            "obi:validationSchema": "https://openbadgespec.org/extensions/exampleExtension/schema.json"
                        }
                    ]
                }
            )},
            {'url': "https://openbadgespec.org/extensions/exampleExtension/schema.json", 'response_body': json.dumps(
                {
                    "$schema": "http://json-schema.org/draft-04/schema#",
                    "title": "1.1 Open Badge Example Extension",
                    "description": "An extension that allows you to add a single string exampleProperty to an extension object to represent some of your favorite text.",
                    "type": "object",
                    "properties": {
                        "exampleProperty": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "exampleProperty"
                    ]
                }
            )},
            {'url': 'http://a.com/instance2', 'response_body': json.dumps(assertion_metadata)},
            {'url': 'http://a.com/badgeclass', 'response_body': json.dumps(badgeclass_metadata)},
            {'url': 'http://a.com/issuer', 'response_body': json.dumps(issuer_metadata)}
        ])
        self.setup_user(email='*****@*****.**', authenticate=True)

        self.assertDictEqual(json.loads(unbake(original_image)), assertion_metadata)

        original_image.seek(0)
        response = self.client.post('/v1/earner/badges', {'image': original_image})
        self.assertEqual(response.status_code, 201)

        public_url = response.data.get('shareUrl')
        self.assertIsNotNone(public_url)
        response = self.client.get(public_url, Accept="application/json")

        for key in ['issuedOn']:
            fetched_ts = dateutil.parser.parse(response.data.get(key))
            metadata_ts = dateutil.parser.parse(assertion_metadata.get(key))
            self.assertEqual(fetched_ts, metadata_ts)

        for key in ['recipient', 'extensions:ExampleExtension']:
            fetched_dict = response.data.get(key)
            self.assertIsNotNone(fetched_dict, "Field '{}' is missing".format(key))
            metadata_dict = assertion_metadata.get(key)
            self.assertDictContainsSubset(metadata_dict, fetched_dict)

        for key in ['schema:unknownMetadata']:
            self.assertEqual(response.data.get(key), assertion_metadata.get(key))