예제 #1
0
    def test_update_dependencies_accept(self, john_doe, normalized_data_id):
        graph = ChangeGraph([{
            '@id': IDObfuscator.encode(john_doe),
            '@type': 'person',
            'given_name': 'Jane',
        }, {
            '@id': '_:456',
            '@type': 'Creator',
            'agent': {
                '@id': IDObfuscator.encode(john_doe),
                '@type': 'person'
            },
            'creative_work': {
                '@id': '_:789',
                '@type': 'preprint'
            },
        }, {
            '@id': '_:789',
            '@type': 'preprint',
            'title': 'All About Cats',
        }])

        change_set = models.ChangeSet.objects.from_graph(
            graph, normalized_data_id)

        change_set.accept()

        john_doe.refresh_from_db()

        assert john_doe.given_name == 'Jane'
        assert models.Preprint.objects.filter(
            agent_relations__agent=john_doe).count() == 1
        assert models.Preprint.objects.filter(
            agent_relations__agent=john_doe).first().title == 'All About Cats'
예제 #2
0
    def test_no_icon(self, schema):
        x = factories.AbstractCreativeWorkFactory()
        source = factories.SourceFactory(icon='')
        x.sources.add(source.user)

        # Have to use % formats because of {}s everywhere
        result = schema.execute('''
            query {
                creativeWork(id: "%s") {
                    id,
                    title,
                    description,
                    sources {
                        title
                    }
                }
            }
        ''' % (IDObfuscator.encode(x), ))

        assert not result.errors

        assert result.data == OrderedDict([
            ('creativeWork', OrderedDict([
                ('id', IDObfuscator.encode(x)),
                ('title', x.title),
                ('description', x.description),
                ('sources', [])
            ]))
        ])
예제 #3
0
 def test_by_id(self, client):
     nd = factories.NormalizedDataFactory(data={'@graph': []})
     resp = client.get('/api/v2/normalizeddata/{}/'.format(IDObfuscator.encode(nd)))
     assert resp.status_code == 200
     assert resp.json()['data']['id'] == IDObfuscator.encode(nd)
     assert resp.json()['data']['type'] == 'NormalizedData'
     assert resp.json()['data']['attributes']['data'] == {'@graph': []}
예제 #4
0
    def test_update_dependencies_accept(self, john_doe, normalized_data_id):
        graph = ChangeGraph([{
            '@id': IDObfuscator.encode(john_doe),
            '@type': 'person',
            'given_name': 'Jane',
        }, {
            '@id': '_:456',
            '@type': 'Creator',
            'agent': {'@id': IDObfuscator.encode(john_doe), '@type': 'person'},
            'creative_work': {'@id': '_:789', '@type': 'preprint'},
        }, {
            '@id': '_:789',
            '@type': 'preprint',
            'title': 'All About Cats',
        }])

        change_set = models.ChangeSet.objects.from_graph(graph, normalized_data_id)

        change_set.accept()

        john_doe.refresh_from_db()

        assert john_doe.given_name == 'Jane'
        assert models.Preprint.objects.filter(agent_relations__agent=john_doe).count() == 1
        assert models.Preprint.objects.filter(agent_relations__agent=john_doe).first().title == 'All About Cats'
예제 #5
0
    def test_no_icon(self):
        x = factories.AbstractCreativeWorkFactory()
        source = factories.SourceFactory(icon='')
        x.sources.add(source.user)

        # Have to use % formats because of {}s everywhere
        result = schema.execute('''
            query {
                creativeWork(id: "%s") {
                    id,
                    title,
                    description,
                    sources {
                        title
                    }
                }
            }
        ''' % (IDObfuscator.encode(x), ))

        assert not result.errors

        assert result.data == OrderedDict([
            ('creativeWork', OrderedDict([
                ('id', IDObfuscator.encode(x)),
                ('title', x.title),
                ('description', x.description),
                ('sources', [])
            ]))
        ])
예제 #6
0
 def test_change_diff(self, graph):
     tag = factories.TagFactory(name='tag1')
     assert graph.create(IDObfuscator.encode(tag), 'tag', {
         'name': 'tag2'
     }).change == {
         'name': 'tag2'
     }
 def test_list_with_items(self, client):
     user = ShareUserFactory()
     banner = SiteBanner.objects.create(
         title='Why wasnt I there',
         description='I could have saved them',
         created_by=user,
         last_modified_by=user,
     )
     resp = client.get('/api/v2/site_banners/')
     assert resp.status_code == 200
     assert resp.json() == {
         'data': [{
             'id': IDObfuscator.encode(banner),
             'type': 'SiteBanner',
             'attributes': {
                 'color': 'info',
                 'icon': 'exclamation',
                 'title': 'Why wasnt I there',
                 'description': 'I could have saved them',
             }
         }],
         'links': {
             'first': 'http://testserver/api/v2/site_banners/?page=1',
             'last': 'http://testserver/api/v2/site_banners/?page=1',
             'next': None,
             'prev': None,
         },
         'meta': {
             'pagination': {'count': 1, 'pages': 1, 'page': 1},
         }
     }
예제 #8
0
    def test_can_delete_work(self, client, normalized_data_id):
        preprint = factories.AbstractCreativeWorkFactory(is_deleted=False)
        preprint.administrative_change(type='share.dataset')
        assert preprint.is_deleted is False

        encoded_id = IDObfuscator.encode(preprint)
        response = client.get('/api/v2/datasets/{}/'.format(encoded_id))
        assert response.status_code == 200

        preprint.administrative_change(is_deleted=True)
        assert preprint.is_deleted is True

        response = client.get('/api/v2/datasets/{}/'.format(encoded_id))
        assert response.status_code == 403
        assert response.json() == {
            "errors": [{
                "source": {
                    "pointer": "/data"
                },
                "detail": "This data set has been removed.",
                "status": "403"
            }]
        }

        response = client.get('/api/v2/datasets/')
        assert response.status_code == 200
        assert response.json() == {
            'data': [],
            'links': {
                'next': None,
                'prev': None
            }
        }
예제 #9
0
    def test_update_dependencies_accept(self, john_doe, normalized_data):
        john_doe_id = IDObfuscator.encode(john_doe)
        graph = MutableGraph.from_jsonld([{
            '@id': john_doe_id,
            '@type': 'person',
            'given_name': 'Jane',
        }, {
            '@id': '_:456',
            '@type': 'Creator',
            'agent': {'@id': john_doe_id, '@type': 'person'},
            'creative_work': {'@id': '_:789', '@type': 'preprint'},
        }, {
            '@id': '_:789',
            '@type': 'preprint',
            'title': 'All About Cats',
        }])

        change_set = ChangeSetBuilder(graph, normalized_data, matches={
            john_doe_id: john_doe,
        }).build_change_set()

        change_set.accept()

        john_doe.refresh_from_db()

        assert john_doe.given_name == 'Jane'
        assert models.Preprint.objects.filter(agent_relations__agent=john_doe).count() == 1
        assert models.Preprint.objects.filter(agent_relations__agent=john_doe).first().title == 'All About Cats'
예제 #10
0
 def test_get_record(self, post, all_about_anteaters):
     ant_id = 'oai:share.osf.io:{}'.format(IDObfuscator.encode(all_about_anteaters))
     parsed = oai_request({'verb': 'GetRecord', 'metadataPrefix': 'oai_dc', 'identifier': ant_id}, post)
     records = parsed.xpath('//ns0:GetRecord/ns0:record', namespaces=NAMESPACES)
     assert len(records) == 1
     assert all_about_anteaters.title == records[0].xpath('ns0:metadata/oai_dc:dc/dc:title', namespaces=NAMESPACES)[0].text
     assert ant_id == records[0].xpath('ns0:header/ns0:identifier', namespaces=NAMESPACES)[0].text
예제 #11
0
파일: views.py 프로젝트: spearous0001/SHARE
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer_class()(data=request.data,
                                                 context={
                                                     'request': request
                                                 })
        serializer.is_valid(raise_exception=True)
        with transaction.atomic():
            # Hack for back-compat: Ingest halfway synchronously, then apply changes asynchronously
            ingester = Ingester(serializer.validated_data['data']).as_user(
                request.user).ingest(apply_changes=False)
            ingester.job.reschedule(claim=True)

            nd_id = models.NormalizedData.objects.filter(
                raw=ingester.raw,
                ingest_jobs=ingester.job).order_by('-created_at').values_list(
                    'id', flat=True).first()

        async_result = ingest.delay(job_id=ingester.job.id, urgent=True)

        # TODO Use an actual serializer
        return Response(
            {
                'id': IDObfuscator.encode_id(nd_id, models.NormalizedData),
                'type': 'NormalizedData',
                'attributes': {
                    'task':
                    async_result.id,
                    'ingest_job':
                    request.build_absolute_uri(
                        reverse('api:ingestjob-detail',
                                args=[IDObfuscator.encode(ingester.job)])),
                }
            },
            status=status.HTTP_202_ACCEPTED)
예제 #12
0
 def test_list_with_items(self, client):
     user = ShareUserFactory()
     banner = SiteBanner.objects.create(
         title='Why wasnt I there',
         description='I could have saved them',
         created_by=user,
         last_modified_by=user,
     )
     resp = client.get('/api/v2/site_banners/')
     assert resp.status_code == 200
     assert resp.json() == {
         'data': [{
             'id': IDObfuscator.encode(banner),
             'type': 'SiteBanner',
             'attributes': {
                 'color': 'info',
                 'icon': 'exclamation',
                 'title': 'Why wasnt I there',
                 'description': 'I could have saved them',
             }
         }],
         'links': {
             'first': 'http://testserver/api/v2/site_banners/?page=1',
             'last': 'http://testserver/api/v2/site_banners/?page=1',
             'next': None,
             'prev': None,
         },
         'meta': {
             'pagination': {
                 'count': 1,
                 'pages': 1,
                 'page': 1
             },
         }
     }
예제 #13
0
    def test_add_multiple_sources(self, celery_app):
        source1 = factories.SourceFactory()
        source2 = factories.SourceFactory()

        work = factories.AbstractCreativeWorkFactory(title='All about Canada')
        data = {
            '@id': IDObfuscator.encode(work),
            '@type': 'creativework',
            'title': 'All aboot Canada'
        }

        nd1 = NormalizedData.objects.create(source=source1.user,
                                            data={'@graph': [data]})
        nd2 = NormalizedData.objects.create(source=source2.user,
                                            data={'@graph': [data]})

        assert work.sources.count() == 0

        celery_app.tasks['share.tasks.disambiguate'](nd1.id)

        work.refresh_from_db()
        assert work.title == 'All aboot Canada'
        assert work.sources.count() == 1

        celery_app.tasks['share.tasks.disambiguate'](nd2.id)

        work.refresh_from_db()
        assert work.title == 'All aboot Canada'
        assert work.sources.count() == 2
예제 #14
0
 def get_url(self, obj, view_name, request, format):
     obfuscated_id = IDObfuscator.encode(obj)
     kwargs = {self.lookup_url_kwarg: obfuscated_id}
     return self.reverse(view_name,
                         kwargs=kwargs,
                         request=request,
                         format=format)
예제 #15
0
 def test_list_records(self, post, all_about_anteaters, django_assert_num_queries):
     with django_assert_num_queries(2):
         parsed = oai_request({'verb': 'ListRecords', 'metadataPrefix': 'oai_dc'}, post)
     records = parsed.xpath('//ns0:ListRecords/ns0:record', namespaces=NAMESPACES)
     assert len(records) == 1
     assert all_about_anteaters.title == records[0].xpath('ns0:metadata/oai_dc:dc/dc:title', namespaces=NAMESPACES)[0].text
     ant_id = 'oai:share.osf.io:{}'.format(IDObfuscator.encode(all_about_anteaters))
     assert ant_id == records[0].xpath('ns0:header/ns0:identifier', namespaces=NAMESPACES)[0].text
예제 #16
0
 def refs(n):
     if isinstance(n, list):
         return [refs(node) for node in n]
     instance = self._get_match(n)
     return {
         '@id': IDObfuscator.encode(instance) if instance else n.id,
         '@type': n.type,
     }
예제 #17
0
 def refs(n):
     if isinstance(n, list):
         return [refs(node) for node in n]
     instance = self._get_match(n)
     return {
         '@id': IDObfuscator.encode(instance) if instance else n.id,
         '@type': n.type,
     }
예제 #18
0
 def test_change_datetime_change(self, graph):
     tag = factories.AbstractCreativeWorkFactory()
     assert graph.create(
         IDObfuscator.encode(tag), 'tag', {
             'date_updated': pendulum.fromtimestamp(0).isoformat()
         }).change == {
             'date_updated': pendulum.fromtimestamp(0).isoformat()
         }
예제 #19
0
 def assert_indexed(self):
     encoded_id = IDObfuscator.encode(self.work)
     doc = self.elastic.es_client.get(index=self.elastic.es_index,
                                      doc_type='creativeworks',
                                      id=encoded_id)
     assert doc['found'] is True
     assert doc['_id'] == encoded_id
     return doc
예제 #20
0
 def delete_works(self, queryset, source_config, dry_run):
     for work in queryset:
         # If we've heard about the work from another source, just remove this source from it instead of deleting
         if len(work.sources.all()) > 1:
             self.stdout.write('{}: {}'.format(
                 self.style.WARNING('Removing {} from {}'.format(
                     source_config.source.name, IDObfuscator.encode(work))),
                 work.title))
             if not dry_run:
                 work.sources.remove(source_config.source.user)
                 # poke it to reindex
                 work.administrative_change(allow_empty=True)
         else:
             self.stdout.write('{}: {}'.format(
                 self.style.NOTICE('Deleting work {}'.format(
                     IDObfuscator.encode(work))), work.title))
             if not dry_run:
                 work.administrative_change(is_deleted=True)
예제 #21
0
    def test_ignore_generic_work_type(self, change_factory, all_about_anteaters):
        cs = change_factory.from_graph({
            '@graph': [{
                '@id': IDObfuscator.encode(all_about_anteaters),
                '@type': 'creativework'
            }]
        }, disambiguate=True)

        assert cs is None
예제 #22
0
 def oai_identifier(self, work):
     if isinstance(work, int):
         share_id = IDObfuscator.encode_id(work, AbstractCreativeWork)
     else:
         share_id = IDObfuscator.encode(work)
     return 'oai{delim}{repository}{delim}{id}'.format(
         id=share_id,
         repository=self.REPOSITORY_IDENTIFIER,
         delim=self.IDENTIFER_DELIMITER)
예제 #23
0
 def assert_indexed(self):
     encoded_id = IDObfuscator.encode(self.work)
     doc = self.elastic.es_client.get(
         index=self.elastic.es_index,
         doc_type='creativeworks',
         id=encoded_id
     )
     assert doc['found'] is True
     assert doc['_id'] == encoded_id
     return doc
예제 #24
0
 def test_oai_errors(self, verb, params, errors, post, all_about_anteaters):
     ant_id = IDObfuscator.encode(all_about_anteaters)
     data = {
         'verb': verb,
         **{k: v.format(id=ant_id)
            for k, v in params.items()}
     }
     actual_errors = oai_request(data, post, errors=True)
     for error_code in errors:
         assert any(
             e.attrib.get('code') == error_code for e in actual_errors)
예제 #25
0
    def delete_works(self, works_qs, source_config, dry_run, superfluous,
                     delete_related):
        works_deleted = []

        if not superfluous:
            works_qs = works_qs.filter(is_deleted=False)
        for work in works_qs.prefetch_related('sources'):
            works_deleted.append(work.id)
            # If we've heard about the work from another source, just remove this source from it instead of deleting
            if len(work.sources.all()) > 1:
                self.stdout.write('{}: {}'.format(
                    self.style.WARNING('Removing {} from {}'.format(
                        source_config.source.name, IDObfuscator.encode(work))),
                    work.title))
                if not dry_run:
                    work.sources.remove(source_config.source.user)
                    # poke it to reindex
                    work.administrative_change(allow_empty=True)
            else:
                self.stdout.write('{}: {}'.format(
                    self.style.NOTICE('Deleting work {}'.format(
                        IDObfuscator.encode(work))), work.title))
                if not dry_run:
                    work.administrative_change(is_deleted=True)
        self.stdout.write('\nProcessed {} works!'.format(len(works_deleted)),
                          style_func=self.style.SUCCESS)
        if not delete_related:
            return

        self.stdout.write('\nNow deleting related works...\n')

        related_works = AbstractCreativeWork.objects.filter(
            Q(incoming_creative_work_relations__subject_id__in=works_deleted) |
            Q(outgoing_creative_work_relations__related_id__in=works_deleted),
            is_deleted=False,
            sources__id=source_config.source.user_id).prefetch_related(
                'sources')

        # Traverse related works only one level deep, please
        self.delete_works(related_works, source_config, dry_run, superfluous,
                          False)
예제 #26
0
 def test_list_identifiers(self, post, all_about_anteaters):
     parsed = oai_request(
         {
             'verb': 'ListIdentifiers',
             'metadataPrefix': 'oai_dc'
         }, post)
     identifiers = parsed.xpath(
         '//ns0:ListIdentifiers/ns0:header/ns0:identifier',
         namespaces=NAMESPACES)
     assert len(identifiers) == 1
     assert identifiers[0].text == 'oai:share.osf.io:{}'.format(
         IDObfuscator.encode(all_about_anteaters))
    def test_by_id(self, client):
        source = Source.objects.first()
        resp = client.get('{}{}/'.format(self.endpoint, IDObfuscator.encode(source)))

        assert resp.status_code == 200
        assert IDObfuscator.load(resp.json()['data']['id']) == source
        assert resp.json()['data']['type'] == 'Source'
        assert resp.json()['data']['attributes'] == {
            'name': source.name,
            'icon': 'http://testserver{}'.format(source.icon.url),
            'homePage': source.home_page,
            'longTitle': source.long_title,
        }
예제 #28
0
    def test_by_id(self, client):
        source = Source.objects.first()
        resp = client.get('{}{}/'.format(self.endpoint, IDObfuscator.encode(source)))

        assert resp.status_code == 200
        assert IDObfuscator.load(resp.json()['data']['id']) == source
        assert resp.json()['data']['type'] == 'Source'
        assert resp.json()['data']['attributes'] == {
            'name': source.name,
            'icon': 'http://testserver{}'.format(source.icon.url),
            'homePage': source.home_page,
            'longTitle': source.long_title,
        }
    def test_get_by_id(self, trusted_user, client):
        reg = models.ProviderRegistration.objects.create(
            contact_name='Tester Testington',
            contact_email='*****@*****.**',
            contact_affiliation='Just some person',
            source_name='PlsWerk',
            submitted_by=trusted_user,
        )

        resp = client.get(
            '/api/v2/sourceregistrations/{}/'.format(IDObfuscator.encode(reg)),
            content_type='application/vnd.api+json',
            HTTP_AUTHORIZATION='Bearer {}'.format(
                trusted_user.accesstoken_set.first()),
        )

        assert resp.status_code == 200
        assert resp.json()['data']['id'] == IDObfuscator.encode(reg)
        assert resp.json()['data']['type'] == 'ProviderRegistration'
        assert resp.json()['data']['attributes'] == {
            'contactAffiliation': 'Just some person',
            'contactEmail': '*****@*****.**',
            'contactName': 'Tester Testington',
            'directSource': False,
            'sourceAdditionalInfo': '',
            'sourceBaseUrl': '',
            'sourceDescription': '',
            'sourceDisallowedSets': '',
            'sourceDocumentation': '',
            'sourceName': 'PlsWerk',
            'sourceOai': False,
            'sourcePreferredMetadataPrefix': '',
            'sourceRateLimit': '',
            'status': 'pending',
            'submittedAt': resp.json()['data']['attributes']['submittedAt']
        }
예제 #30
0
    def test_change_existing(self, change_factory, jane_doe):
        change_set = change_factory.from_graph({
            '@graph': [{
                '@id': IDObfuscator.encode(jane_doe),
                '@type': 'Person',
                'given_name': 'John'
            }]
        }, disambiguate=True)

        assert change_set.changes.first().target == jane_doe

        assert jane_doe.given_name == 'Jane'

        change_set.accept()
        jane_doe.refresh_from_db()

        assert jane_doe.given_name == 'John'
예제 #31
0
    def test_date_updated_update(self, change_ids, change_factory, all_about_anteaters):
        """
        Submitting an identical date as a string should be recognized as no change.
        """
        all_about_anteaters.date_updated = pendulum.now()
        all_about_anteaters.change_id = change_ids.get()
        all_about_anteaters.save()

        change_set = change_factory.from_graph({
            '@graph': [{
                '@type': 'article',
                '@id': IDObfuscator.encode(all_about_anteaters),
                'date_updated': str(all_about_anteaters.date_updated)
            }]
        }, disambiguate=True)

        assert change_set is None
예제 #32
0
 def create(self, request, *args, **kwargs):
     serializer = self.get_serializer_class()(data=request.data,
                                              context={
                                                  'request': request
                                              })
     if serializer.is_valid(raise_exception=True):
         nm_instance = serializer.save()
         async_result = disambiguate.delay(nm_instance.id)
         # TODO Fix Me
         return Response(
             {
                 'id': IDObfuscator.encode(nm_instance),
                 'type': 'NormalizedData',
                 'attributes': {
                     'task': async_result.id
                 }
             },
             status=status.HTTP_202_ACCEPTED)
예제 #33
0
    def test_work_type_stays_nongeneric(self, change_factory, all_about_anteaters):
        new_title = 'Some about Anteaters'
        cs = change_factory.from_graph({
            '@graph': [{
                '@id': IDObfuscator.encode(all_about_anteaters),
                '@type': 'creativework',
                'title': new_title
            }]
        }, disambiguate=True)

        assert all_about_anteaters.type == 'share.article'
        assert models.Publication.objects.count() == 1

        cs.accept()
        all_about_anteaters.refresh_from_db()

        assert all_about_anteaters.type == 'share.article'
        assert all_about_anteaters.title == new_title
예제 #34
0
    def test_change_agent_type(self, change_factory, university_of_whales):
        cs = change_factory.from_graph({
            '@graph': [{
                '@id': IDObfuscator.encode(university_of_whales),
                '@type': 'consortium'
            }]
        }, disambiguate=True)

        assert models.Institution.objects.count() == 1
        assert models.Consortium.objects.count() == 0

        (org,) = cs.accept()

        assert org.type == 'share.consortium'
        assert org.id == university_of_whales.id
        assert org.name == university_of_whales.name
        assert models.Institution.objects.count() == 0
        assert models.Consortium.objects.count() == 1
    def test_can_delete_work(self, client, normalized_data_id):
        preprint = factories.AbstractCreativeWorkFactory(is_deleted=False)
        preprint.administrative_change(type='share.dataset')
        assert preprint.is_deleted is False

        encoded_id = IDObfuscator.encode(preprint)
        response = client.get('/api/v2/datasets/{}/'.format(encoded_id))
        assert response.status_code == 200

        preprint.administrative_change(is_deleted=True)
        assert preprint.is_deleted is True

        response = client.get('/api/v2/datasets/{}/'.format(encoded_id))
        assert response.status_code == 403
        assert response.json() == {"errors": [{"source": {"pointer": "/data"}, "detail": "This data set has been removed.", "status": "403"}]}

        response = client.get('/api/v2/datasets/')
        assert response.status_code == 200
        assert response.json() == {'data': [], 'links': {'next': None, 'prev': None}}
예제 #36
0
    def test_add_multiple_sources(self):
        source1 = factories.SourceFactory()
        source2 = factories.SourceFactory()

        work = factories.AbstractCreativeWorkFactory(title='All about Canada')
        data = [{'@id': IDObfuscator.encode(work), '@type': 'creativework', 'title': 'All aboot Canada'}]

        assert work.sources.count() == 0

        Ingester(data).as_user(source1.user).ingest(index=False)

        work.refresh_from_db()
        assert work.title == 'All aboot Canada'
        assert work.sources.count() == 1

        Ingester(data).as_user(source2.user).ingest(index=False)

        work.refresh_from_db()
        assert work.title == 'All aboot Canada'
        assert work.sources.count() == 2
예제 #37
0
    def test_order(self, client, order):
        resp = client.get('/api/v2/atom', {'order': order})
        assert resp.status_code == 200

        feed = etree.fromstring(resp.content)
        works = AbstractCreativeWork.objects.order_by('-' + order).exclude(
            **{order: None})

        assert len(feed.xpath('//atom:entry', namespaces=NAMESPACES)) == 11

        for creative_work, entry in zip(
                works,
                feed.xpath('//atom:entry',
                           namespaces={'atom':
                                       'http://www.w3.org/2005/Atom'})):
            assert entry.find(
                'atom:title',
                namespaces=NAMESPACES).text == creative_work.title
            assert entry.find(
                'atom:summary',
                namespaces=NAMESPACES).text == creative_work.description
            assert entry.find('atom:link',
                              namespaces=NAMESPACES).attrib['href'].endswith(
                                  IDObfuscator.encode(creative_work))

            if getattr(creative_work, order):
                assert entry.find(
                    'atom:updated', namespaces=NAMESPACES).text == getattr(
                        creative_work,
                        order).replace(microsecond=0).isoformat()
            else:
                assert entry.find('atom:updated',
                                  namespaces=NAMESPACES).text is None

            if creative_work.date_published:
                assert entry.find(
                    'atom:published', namespaces=NAMESPACES
                ).text == creative_work.date_published.isoformat()
            else:
                assert entry.find('atom:published',
                                  namespaces=NAMESPACES) is None
    def test_get_data(self, generator, model, route, controlled_values, client, Graph, ingest):
        ingest(Graph(initial))

        graph = Graph(*generator)
        Regulator().regulate(graph)
        matches = Matcher(DatabaseStrategy()).find_all_matches(graph)

        for node in graph:
            if node.type == model:
                expected = node
                expected_id = IDObfuscator.encode(matches[node])
                break
        response = client.get('/api/v2/{}/{}/'.format(route, expected_id))

        actual = json.loads(response.content.decode(encoding='UTF-8'))

        assert response.status_code == 200
        assert actual['data']['id'] == expected_id
        assert actual['data']['attributes']['type'] == expected.type
        for value in controlled_values:
            assert actual['data']['attributes'][value] == expected[camelCase_to_underscore(value)]
예제 #39
0
    def post(self, request, *args, **kwargs):

        try:
            jsonschema.validate(request.data, v1_schemas.v1_push_schema)
        except (jsonschema.exceptions.ValidationError) as error:
            raise ParseError(detail=error.message)

        try:
            prelim_data = request.data['jsonData']
        except ParseError as error:
            return Response('Invalid JSON - {0}'.format(error.message),
                            status=status.HTTP_400_BAD_REQUEST)

        # store raw data, assuming you can only submit one at a time
        with transaction.atomic():
            try:
                doc_id = prelim_data['uris']['canonicalUri']
            except KeyError:
                return Response(
                    {
                        'errors': 'Canonical URI not found in uris.',
                        'data': prelim_data
                    },
                    status=status.HTTP_400_BAD_REQUEST)

            ingester = Ingester(prelim_data,
                                doc_id).as_user(request.user,
                                                'v1_push').ingest_async()

            return Response(
                {
                    'task_id':
                    ingester.async_task.id,
                    'ingest_job':
                    request.build_absolute_uri(
                        reverse('api:ingestjob-detail',
                                args=[IDObfuscator.encode(ingester.job)])),
                },
                status=status.HTTP_202_ACCEPTED)
    def delete_works(self, works_qs, source_config, dry_run, superfluous, delete_related):
        works_deleted = []

        if not superfluous:
            works_qs = works_qs.filter(is_deleted=False)
        for work in works_qs.prefetch_related('sources'):
            works_deleted.append(work.id)
            # If we've heard about the work from another source, just remove this source from it instead of deleting
            if len(work.sources.all()) > 1:
                self.stdout.write('{}: {}'.format(
                    self.style.WARNING('Removing {} from {}'.format(source_config.source.name, IDObfuscator.encode(work))),
                    work.title
                ))
                if not dry_run:
                    work.sources.remove(source_config.source.user)
                    # poke it to reindex
                    work.administrative_change(allow_empty=True)
            else:
                self.stdout.write('{}: {}'.format(
                    self.style.NOTICE('Deleting work {}'.format(IDObfuscator.encode(work))),
                    work.title
                ))
                if not dry_run:
                    work.administrative_change(is_deleted=True)
        self.stdout.write('\nProcessed {} works!'.format(len(works_deleted)), style_func=self.style.SUCCESS)
        if not delete_related:
            return

        self.stdout.write('\nNow deleting related works...\n')

        related_works = AbstractCreativeWork.objects.filter(
            Q(incoming_creative_work_relations__subject_id__in=works_deleted) | Q(outgoing_creative_work_relations__related_id__in=works_deleted),
            is_deleted=False,
            sources__id=source_config.source.user_id
        ).prefetch_related('sources')

        # Traverse related works only one level deep, please
        self.delete_works(related_works, source_config, dry_run, superfluous, False)
예제 #41
0
    def test_order(self, client, order):
        resp = client.get('/api/v2/atom', {'order': order})
        assert resp.status_code == 200

        feed = etree.fromstring(resp.content)
        works = AbstractCreativeWork.objects.order_by('-' + order).exclude(**{order: None})

        assert len(feed.xpath('//atom:entry', namespaces=NAMESPACES)) == 11

        for creative_work, entry in zip(works, feed.xpath('//atom:entry', namespaces={'atom': 'http://www.w3.org/2005/Atom'})):
            try:
                contributors = list(AbstractAgentWorkRelation.objects.filter(creative_work_id=creative_work.id))
                first_contributor = AbstractAgentWorkRelation.objects.get(creative_work_id=creative_work.id, order_cited=0)
            except Exception:
                contributors = None

            assert entry.find('atom:title', namespaces=NAMESPACES).text == creative_work.title
            assert entry.find('atom:summary', namespaces=NAMESPACES).text == creative_work.description
            assert entry.find('atom:link', namespaces=NAMESPACES).attrib['href'].endswith(IDObfuscator.encode(creative_work))

            if not contributors:
                assert entry.find('atom:author', namespaces=NAMESPACES)[0].text == 'No authors provided.'
            elif len(contributors) > 1:
                assert entry.find('atom:author', namespaces=NAMESPACES)[0].text == '{} et al.'.format(first_contributor.agent.name)
            else:
                assert entry.find('atom:author', namespaces=NAMESPACES)[0].text == first_contributor.agent.name

            if getattr(creative_work, order):
                assert entry.find('atom:updated', namespaces=NAMESPACES).text == getattr(creative_work, order).replace(microsecond=0).isoformat()
            else:
                assert entry.find('atom:updated', namespaces=NAMESPACES).text is None

            if creative_work.date_published:
                assert entry.find('atom:published', namespaces=NAMESPACES).text == creative_work.date_published.isoformat()
            else:
                assert entry.find('atom:published', namespaces=NAMESPACES) is None
예제 #42
0
 def encoded_id(self, obj):
     return IDObfuscator.encode(obj)
예제 #43
0
 def serialize_subject(self, subject):
     return {
         'id': IDObfuscator.encode(subject),
         'type': 'subject',
         'name': safe_substr(subject.name),
     }
예제 #44
0
    def post(self, request, *args, **kwargs):

        try:
            jsonschema.validate(request.data, v1_schemas.v1_push_schema)
        except (jsonschema.exceptions.ValidationError) as error:
            raise ParseError(detail=error.message)

        try:
            prelim_data = request.data['jsonData']
        except ParseError as error:
            return Response(
                'Invalid JSON - {0}'.format(error.message),
                status=status.HTTP_400_BAD_REQUEST
            )

        # store raw data, assuming you can only submit one at a time
        with transaction.atomic():
            try:
                doc_id = prelim_data['uris']['canonicalUri']
            except KeyError:
                return Response({'errors': 'Canonical URI not found in uris.', 'data': prelim_data}, status=status.HTTP_400_BAD_REQUEST)

            ingester = Ingester(prelim_data, doc_id).as_user(request.user, 'v1_push').ingest_async(urgent=True)

            return Response({
                'task_id': ingester.async_task.id,
                'ingest_job': request.build_absolute_uri(reverse('api:ingestjob-detail', args=[IDObfuscator.encode(ingester.job)])),
            }, status=status.HTTP_202_ACCEPTED)
예제 #45
0
 def test_load_instance(self, graph):
     tag = factories.TagFactory()
     assert graph.create(IDObfuscator.encode(tag), 'tag', {}).instance == tag
예제 #46
0
 def id(self):
     return (self.instance and IDObfuscator.encode(self.instance)) or self._id
예제 #47
0
 def get_url(self, obj, view_name, request, format):
     obfuscated_id = IDObfuscator.encode(obj)
     kwargs = {self.lookup_url_kwarg: obfuscated_id}
     return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
예제 #48
0
 def test_change_no_diff(self, graph):
     tag = factories.TagFactory()
     assert graph.create(IDObfuscator.encode(tag), 'tag', {'name': tag.name}).change == {}
예제 #49
0
 def test_change_diff(self, graph):
     tag = factories.TagFactory(name='tag1')
     assert graph.create(IDObfuscator.encode(tag), 'tag', {'name': 'tag2'}).change == {'name': 'tag2'}
예제 #50
0
 def test_change_datetime_no_change(self, graph):
     work = factories.AbstractCreativeWorkFactory()
     assert graph.create(IDObfuscator.encode(work), work._meta.model_name, {'date_updated': work.date_updated.isoformat()}).change == {}
예제 #51
0
 def test_change_datetime_change(self, graph):
     tag = factories.AbstractCreativeWorkFactory()
     assert graph.create(IDObfuscator.encode(tag), 'tag', {'date_updated': pendulum.fromtimestamp(0).isoformat()}).change == {'date_updated': pendulum.fromtimestamp(0).isoformat()}
예제 #52
0
 def test_list_identifiers(self, post, all_about_anteaters):
     parsed = oai_request({'verb': 'ListIdentifiers', 'metadataPrefix': 'oai_dc'}, post)
     identifiers = parsed.xpath('//ns0:ListIdentifiers/ns0:header/ns0:identifier', namespaces=NAMESPACES)
     assert len(identifiers) == 1
     assert identifiers[0].text == 'oai:share.osf.io:{}'.format(IDObfuscator.encode(all_about_anteaters))
예제 #53
0
 def test_oai_errors(self, verb, params, errors, post, all_about_anteaters):
     ant_id = IDObfuscator.encode(all_about_anteaters)
     data = {'verb': verb, **{k: v.format(id=ant_id) for k, v in params.items()}}
     actual_errors = oai_request(data, post, errors=True)
     for error_code in errors:
         assert any(e.attrib.get('code') == error_code for e in actual_errors)
예제 #54
0
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer_class()(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        with transaction.atomic():
            # Hack for back-compat: Ingest halfway synchronously, then apply changes asynchronously
            ingester = Ingester(serializer.validated_data['data']).as_user(request.user).ingest(apply_changes=False)
            ingester.job.reschedule(claim=True)

            nd_id = models.NormalizedData.objects.filter(
                raw=ingester.raw,
                ingest_jobs=ingester.job
            ).order_by('-created_at').values_list('id', flat=True).first()

        async_result = ingest.delay(job_id=ingester.job.id, urgent=True)

        # TODO Use an actual serializer
        return Response({
            'id': IDObfuscator.encode_id(nd_id, models.NormalizedData),
            'type': 'NormalizedData',
            'attributes': {
                'task': async_result.id,
                'ingest_job': request.build_absolute_uri(reverse('api:ingestjob-detail', args=[IDObfuscator.encode(ingester.job)])),
            }
        }, status=status.HTTP_202_ACCEPTED)
예제 #55
0
 def serialize_tag(self, tag):
     return {
         'id': IDObfuscator.encode(tag),
         'type': 'tag',
         'name': safe_substr(tag.name),
     }