コード例 #1
0
    def test_update_from_request(self):
        # create test note to update
        note = Annotation(text="Here's the thing",
                          quote="really",
                          extra_data=json.dumps({'sample data': 'foobar'}))
        note.save()

        # permissions check requires a real user
        user = get_user_model().objects.get(username='******')
        self.mockrequest.user = user

        with patch.object(note, 'db_permissions') as mock_db_perms:
            note.update_from_request(self.mockrequest)
            self.assertEqual(self.annotation_data['text'], note.text)
            self.assertEqual(self.annotation_data['quote'], note.quote)
            self.assertEqual(self.annotation_data['uri'], note.uri)
            self.assert_('ranges' in note.extra_data)
            self.assertEqual(self.annotation_data['ranges'][0]['start'],
                             note.extra_data['ranges'][0]['start'])
            self.assert_('permissions' not in note.extra_data)
            # existing extra data should no longer present
            self.assert_('sample data' not in note.extra_data)

            # testuser does not have admin on this annotation;
            # permissions should not be updated
            mock_db_perms.assert_not_called()

            # give user admin permission and update again
            note.assign_permission('admin_annotation', user)
            note.update_from_request(self.mockrequest)
            mock_db_perms.assert_called_with(
                self.annotation_data['permissions'])
コード例 #2
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_update_from_request(self):
        # create test note to update
        note = Annotation(text="Here's the thing", quote="really",
            extra_data=json.dumps({'sample data': 'foobar'}))
        note.save()

        # permissions check requires a real user
        user = get_user_model().objects.get(username='******')
        self.mockrequest.user = user

        with patch.object(note, 'db_permissions') as mock_db_perms:
            note.update_from_request(self.mockrequest)
            self.assertEqual(self.annotation_data['text'], note.text)
            self.assertEqual(self.annotation_data['quote'], note.quote)
            self.assertEqual(self.annotation_data['uri'], note.uri)
            self.assert_('ranges' in note.extra_data)
            self.assertEqual(self.annotation_data['ranges'][0]['start'],
                note.extra_data['ranges'][0]['start'])
            self.assert_('permissions' not in note.extra_data)
            # existing extra data should no longer present
            self.assert_('sample data' not in note.extra_data)

            # testuser does not have admin on this annotation;
            # permissions should not be updated
            mock_db_perms.assert_not_called()

            # give user admin permission and update again
            note.assign_permission('admin_annotation', user)
            note.update_from_request(self.mockrequest)
            mock_db_perms.assert_called_with(self.annotation_data['permissions'])
コード例 #3
0
    def test_related_pages(self):
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(len(self.annotation_data['related_pages']),
                         len(note.related_pages))
        for idx in range(len(self.annotation_data['related_pages'])):
            self.assertEqual(self.annotation_data['related_pages'][idx],
                             note.related_pages[idx])
            self.assertEqual(self.annotation_data['related_pages'][idx],
                             note.extra_data['related_pages'][idx])

        note = Annotation()
        self.assertEqual(None, note.related_pages)
コード例 #4
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_create_from_request(self):
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(self.annotation_data['text'], note.text)
        self.assertEqual(self.annotation_data['quote'], note.quote)
        self.assertEqual(self.annotation_data['uri'], note.uri)
        self.assert_('ranges' in note.extra_data)
        self.assertEqual(self.annotation_data['ranges'][0]['start'],
            note.extra_data['ranges'][0]['start'])
        self.assert_('permissions' in note.extra_data)

        # create from request with user specified
        user = get_user_model().objects.get(username='******')
        self.mockrequest.user = user
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(user, note.user)
コード例 #5
0
    def test_create_from_request(self):
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(self.annotation_data['text'], note.text)
        self.assertEqual(self.annotation_data['quote'], note.quote)
        self.assertEqual(self.annotation_data['uri'], note.uri)
        self.assert_('ranges' in note.extra_data)
        self.assertEqual(self.annotation_data['ranges'][0]['start'],
                         note.extra_data['ranges'][0]['start'])
        self.assert_('permissions' in note.extra_data)

        # create from request with user specified
        user = get_user_model().objects.get(username='******')
        self.mockrequest.user = user
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(user, note.user)
コード例 #6
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_user_permissions(self):
        # annotation user/owner automatically gets permissions
        user = get_user_model().objects.get(username='******')
        note = Annotation.create_from_request(self.mockrequest)
        note.user = user
        note.save()

        user_perms = note.user_permissions()
        self.assertEqual(4, user_perms.count())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='view_annotation')
                               .exists())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='change_annotation')
                               .exists())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='delete_annotation')
                               .exists())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='admin_annotation')
                               .exists())

        note.save()
        # saving again shouldn't duplicate the permissions
        self.assertEqual(4, note.user_permissions().count())
コード例 #7
0
    def test_permissions_dict(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()
        # get some users and groups to work with
        user = get_user_model().objects.get(username='******')
        group1 = AnnotationGroup.objects.create(name='foo')
        group2 = AnnotationGroup.objects.create(name='foobar')

        perms = {
            'read':
            [user.username, group1.annotation_id, group2.annotation_id],
            'update': [user.username, group1.annotation_id],
            'delete': [user.username],
            'admin': []
        }
        # test round-trip: convert to db permissions and then back
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())

        perms = {
            'read': [user.username, group1.annotation_id],
            'update': [user.username],
            'delete': [],
            'admin': []
        }
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())

        perms = {'read': [], 'update': [], 'delete': [], 'admin': []}
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())
コード例 #8
0
    def test_user_permissions(self):
        # annotation user/owner automatically gets permissions
        user = get_user_model().objects.get(username='******')
        note = Annotation.create_from_request(self.mockrequest)
        note.user = user
        note.save()

        user_perms = note.user_permissions()
        self.assertEqual(4, user_perms.count())
        self.assert_(
            user_perms.filter(user=user,
                              permission__codename='view_annotation').exists())
        self.assert_(
            user_perms.filter(
                user=user, permission__codename='change_annotation').exists())
        self.assert_(
            user_perms.filter(
                user=user, permission__codename='delete_annotation').exists())
        self.assert_(
            user_perms.filter(
                user=user, permission__codename='admin_annotation').exists())

        note.save()
        # saving again shouldn't duplicate the permissions
        self.assertEqual(4, note.user_permissions().count())
コード例 #9
0
ファイル: tests.py プロジェクト: WSULib/readux
    def last_updated_time(self):
        Annotation.objects.all().delete()  # delete fixture annotations
        self.assertEqual(None, Annotation.objects.all().last_updated_time())

        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        self.assertEqual(note.updated,
                         Annotation.objects.all().last_updated_time())
コード例 #10
0
    def last_updated_time(self):
        Annotation.objects.all().delete()  # delete fixture annotations
        self.assertEqual(None, Annotation.objects.all().last_updated_time())

        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        self.assertEqual(note.updated,
                         Annotation.objects.all().last_updated_time())
コード例 #11
0
    def test_last_created_time(self):
        # test custom queryset methods
        Annotation.objects.all().delete()  # delete fixture annotations
        self.assertEqual(None, Annotation.objects.all().last_created_time())

        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        self.assertEqual(note.created,
                         Annotation.objects.all().last_created_time())
コード例 #12
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_last_created_time(self):
        # test custom queryset methods
        Annotation.objects.all().delete()  # delete fixture annotations
        self.assertEqual(None, Annotation.objects.all().last_created_time())

        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        self.assertEqual(note.created,
                         Annotation.objects.all().last_created_time())
コード例 #13
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_related_pages(self):
        note = Annotation.create_from_request(self.mockrequest)
        self.assertEqual(len(self.annotation_data['related_pages']),
            len(note.related_pages))
        for idx in range(len(self.annotation_data['related_pages'])):
            self.assertEqual(self.annotation_data['related_pages'][idx],
                note.related_pages[idx])
            self.assertEqual(self.annotation_data['related_pages'][idx],
                note.extra_data['related_pages'][idx])

        note = Annotation()
        self.assertEqual(None, note.related_pages)
コード例 #14
0
ファイル: views.py プロジェクト: WSULib/readux
    def post(self, request):
        'Create a new annotation via AJAX.'
        # for now, only support creation via ajax
        if request.is_ajax():
            note = Annotation.create_from_request(request)
            note.save()
            # annotator store documentation says to return 303
            # not sure why this isn't a 201 Created...
            return HttpResponseSeeOtherRedirect(note.get_absolute_url())

        else:
            return HttpResponseBadRequest(non_ajax_error_msg)
コード例 #15
0
ファイル: annotate.py プロジェクト: saracarl/readux
    def test_annotation_to_tei(self):
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR, 'teifacsimile.xml'),
            tei.AnnotatedFacsimile)

        note = Annotation(text="Here's the thing", quote="really",
            extra_data=json.dumps({'sample data': 'foobar',
                'tags': ['test', 'one', 'two']}))

        teinote = annotation_to_tei(note, teidoc)
        self.assert_(isinstance(teinote, tei.Note))
        self.assertEqual('annotation-%s' % note.id, teinote.id)
        self.assert_(teinote.href.endswith(note.get_absolute_url()))
        self.assertEqual(note.text, teinote.paragraphs[0])

        # todo: add a schema validation once we get the output to be valid
        # teidoc.schema_valid()
        # access errors with teidoc.schema_validation_errors()

        # annotation user should be set as note response
        user = get_user_model()(username='******')
        user.save()
        note.user = user
        teinote = annotation_to_tei(note, teidoc)
        self.assertEqual(user.username, teinote.resp)

        # tags should be set as interp ids ana attribute
        for tag in note.info()['tags']:
            self.assert_('#%s' % tag in teinote.ana)

        # test that markdown formatting is coming through
        footnote = '''Footnotes[^1] have a label and content.

[^1]: This is some footnote content.'''
        note.text = footnote
        teinote = annotation_to_tei(note, teidoc)
        self.assert_('<ref target="#fn1" type="noteAnchor">1</ref>' in
            teinote.serialize())

        # markdown should be included in a code element
        self.assertEqual(note.text, teinote.markdown)

        # related page references
        rel_pages = [
            'http://testpid.co/ark:/1234/11',
            'http://testpid.co/ark:/1234/22',
            'http://testpid.co/ark:/1234/qq'
        ]
        note.extra_data = json.dumps({'related_pages': rel_pages})
        teinote = annotation_to_tei(note, teidoc)
        self.assertEqual(len(rel_pages), len(teinote.related_pages))
        # first ark has a corresponding id in the fixture, should be converted
        self.assertEqual('#%s' % teidoc.page_id_by_xlink(rel_pages[0]),
            teinote.related_pages[0].target)
        for idx in range(len(rel_pages)):
            self.assertEqual(rel_pages[idx], teinote.related_pages[idx].text)
コード例 #16
0
ファイル: import_annotations.py プロジェクト: un33k/readux
    def import_annotation(self, data):
        '''Create and save a new annotation, setting fields based on a
        dictionary of data passed in.  Raises an error if an annotation
        author is not found as a user in the database.'''
        note = Annotation()

        # NOTE: because we are using uuid for annotation id field,
        # importing an annotation twice does not error, but simply
        # replaces the old copy.  Might want to add checks for this...

        # required fields that should always be present
        # (not normally set by user)
        for field in ['updated', 'created', 'id']:
            setattr(note, field, data[field])
            del data[field]
        # user is special: annotation data only includes username,
        # but we need a user object
        # NOTE: this could result in making one person's annotations
        # available to someone else, if someone is using a different
        # username in another instance
        if 'user' in data:
            try:
                note.user = get_user_model().objects.get(username=data['user'])
                del data['user']
            except get_user_model().DoesNotExist:
                raise CommandError(
                    'Cannot import annotations for user %s (does not exist)' %
                    data['user'])

        for field in Annotation.common_fields:
            if field in data:
                setattr(note, field, data[field])
                del data[field]

        # put any other data that is left in extra data json field
        if data:
            note.extra_data.update(data)

        note.save()
コード例 #17
0
ファイル: import_annotations.py プロジェクト: WSULib/readux
    def import_annotation(self, data):
        '''Create and save a new annotation, setting fields based on a
        dictionary of data passed in.  Raises an error if an annotation
        author is not found as a user in the database.'''
        note = Annotation()

        # NOTE: because we are using uuid for annotation id field,
        # importing an annotation twice does not error, but simply
        # replaces the old copy.  Might want to add checks for this...

        # required fields that should always be present
        # (not normally set by user)
        for field in ['updated', 'created', 'id']:
            setattr(note, field, data[field])
            del data[field]
        # user is special: annotation data only includes username,
        # but we need a user object
        # NOTE: this could result in making one person's annotations
        # available to someone else, if someone is using a different
        # username in another instance
        if 'user' in data:
            try:
                note.user = get_user_model().objects.get(username=data['user'])
                del data['user']
            except get_user_model().DoesNotExist:
                raise CommandError('Cannot import annotations for user %s (does not exist)' % data['user'])

        for field in Annotation.common_fields:
            if field in data:
                setattr(note, field, data[field])
                del data[field]

        # put any other data that is left in extra data json field
        if data:
            note.extra_data.update(data)

        note.save()
コード例 #18
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_info(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        info = note.info()
        fields = ['id', 'annotator_schema_version', 'created', 'updated',
            'text', 'quote', 'uri', 'user', 'ranges', 'permissions']
        # test that expected fields are present
        for f in fields:
            self.assert_(f in info)
        # test that dates are in isoformat
        self.assertEqual(info['created'], note.created.isoformat())
        self.assertEqual(info['updated'], note.updated.isoformat())

        # associate note with a user
        user = get_user_model().objects.get(username='******')
        note.user = user
        info = note.info()
        self.assertEqual(user.username, info['user'])
コード例 #19
0
    def test_info(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()  # save so created/updated will get set
        info = note.info()
        fields = [
            'id', 'annotator_schema_version', 'created', 'updated', 'text',
            'quote', 'uri', 'user', 'ranges', 'permissions'
        ]
        # test that expected fields are present
        for f in fields:
            self.assert_(f in info)
        # test that dates are in isoformat
        self.assertEqual(info['created'], note.created.isoformat())
        self.assertEqual(info['updated'], note.updated.isoformat())

        # associate note with a user
        user = get_user_model().objects.get(username='******')
        note.user = user
        info = note.info()
        self.assertEqual(user.username, info['user'])
コード例 #20
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_permissions_dict(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()
        # get some users and groups to work with
        user = get_user_model().objects.get(username='******')
        group1 = AnnotationGroup.objects.create(name='foo')
        group2 = AnnotationGroup.objects.create(name='foobar')

        perms = {
            'read': [user.username, group1.annotation_id,
                     group2.annotation_id],
            'update': [user.username, group1.annotation_id],
            'delete': [user.username],
            'admin': []
        }
        # test round-trip: convert to db permissions and then back
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())

        perms = {
            'read': [user.username, group1.annotation_id],
            'update': [user.username],
            'delete': [],
            'admin': []
        }
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())

        perms = {
            'read': [],
            'update': [],
            'delete': [],
            'admin': []
        }
        note.db_permissions(perms)
        self.assertEqual(perms, note.permissions_dict())
コード例 #21
0
    def test_db_permissions(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()
        # get some users and groups to work with
        user = get_user_model().objects.get(username='******')
        group1 = AnnotationGroup.objects.create(name='foo')
        group2 = AnnotationGroup.objects.create(name='foobar')

        note.db_permissions({
            'read':
            [user.username, group1.annotation_id, group2.annotation_id],
            'update': [user.username, group1.annotation_id],
            'delete': [user.username]
        })

        # inspect the db permissions created

        # should be two total user permissions, one to view and one to change
        user_perms = note.user_permissions()
        self.assertEqual(3, user_perms.count())
        self.assert_(
            user_perms.filter(user=user,
                              permission__codename='view_annotation').exists())
        self.assert_(
            user_perms.filter(
                user=user, permission__codename='change_annotation').exists())
        self.assert_(
            user_perms.filter(
                user=user, permission__codename='delete_annotation').exists())

        # should be three total group permissions
        group_perms = note.group_permissions()
        self.assertEqual(3, group_perms.count())
        self.assert_(
            group_perms.filter(
                group=group1, permission__codename='view_annotation').exists())
        self.assert_(
            group_perms.filter(
                group=group1,
                permission__codename='change_annotation').exists())
        self.assert_(
            group_perms.filter(
                group=group2, permission__codename='view_annotation').exists())

        # updating the permissions for the same note should
        # remove permissions that no longer apply
        note.db_permissions({
            'read': [user.username, group1.annotation_id],
            'update': [user.username],
            'delete': []
        })

        # counts should reflect the changes
        user_perms = note.user_permissions()
        self.assertEqual(2, user_perms.count())
        group_perms = note.group_permissions()
        self.assertEqual(1, group_perms.count())

        # permissions created before should be gone
        self.assertFalse(
            user_perms.filter(
                user=user, permission__codename='delete_annotation').exists())
        self.assertFalse(
            group_perms.filter(
                group=group1,
                permission__codename='change_annotation').exists())
        self.assertFalse(
            group_perms.filter(
                group=group2, permission__codename='view_annotation').exists())

        # invalid group/user should not error
        note.db_permissions({
            'read': ['bogus', 'group:666', 'group:foo'],
            'update': ['group:__world__'],
            'delete': []
        })

        self.assertEqual(0, note.user_permissions().count())
        self.assertEqual(0, note.group_permissions().count())
コード例 #22
0
ファイル: tests.py プロジェクト: WSULib/readux
    def test_db_permissions(self):
        note = Annotation.create_from_request(self.mockrequest)
        note.save()
        # get some users and groups to work with
        user = get_user_model().objects.get(username='******')
        group1 = AnnotationGroup.objects.create(name='foo')
        group2 = AnnotationGroup.objects.create(name='foobar')

        note.db_permissions({
            'read': [user.username, group1.annotation_id,
                     group2.annotation_id],
            'update': [user.username, group1.annotation_id],
            'delete': [user.username]
        })

        # inspect the db permissions created

        # should be two total user permissions, one to view and one to change
        user_perms = note.user_permissions()
        self.assertEqual(3, user_perms.count())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='view_annotation')
                               .exists())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='change_annotation')
                               .exists())
        self.assert_(user_perms.filter(user=user,
                                       permission__codename='delete_annotation')
                               .exists())

        # should be three total group permissions
        group_perms = note.group_permissions()
        self.assertEqual(3, group_perms.count())
        self.assert_(group_perms.filter(group=group1,
                                        permission__codename='view_annotation')
                                .exists())
        self.assert_(group_perms.filter(group=group1,
                                        permission__codename='change_annotation')
                                .exists())
        self.assert_(group_perms.filter(group=group2,
                                        permission__codename='view_annotation')
                                .exists())

        # updating the permissions for the same note should
        # remove permissions that no longer apply
        note.db_permissions({
            'read': [user.username, group1.annotation_id],
            'update': [user.username],
            'delete': []
        })

        # counts should reflect the changes
        user_perms = note.user_permissions()
        self.assertEqual(2, user_perms.count())
        group_perms = note.group_permissions()
        self.assertEqual(1, group_perms.count())

        # permissions created before should be gone
        self.assertFalse(user_perms.filter(user=user,
                                           permission__codename='delete_annotation')
                                   .exists())
        self.assertFalse(group_perms.filter(group=group1,
                                            permission__codename='change_annotation')
                                    .exists())
        self.assertFalse(group_perms.filter(group=group2,
                                            permission__codename='view_annotation')
                                    .exists())

        # invalid group/user should not error
        note.db_permissions({
            'read': ['bogus', 'group:666', 'group:foo'],
            'update': ['group:__world__'],
            'delete': []
        })

        self.assertEqual(0, note.user_permissions().count())
        self.assertEqual(0, note.group_permissions().count())
コード例 #23
0
ファイル: annotate.py プロジェクト: saracarl/readux
    def test_annotated_tei(self):
        # create annotation with a user
        user = get_user_model()(username='******',
            first_name="Anne", last_name="O'Tater")
        user.save()
        page_uri = "http://readux.co/books/pages/some:1/"
        note = Annotation(text="Here's the thing", quote="really",
            uri=page_uri,
            extra_data=json.dumps({
                'sample data': 'foobar',
                'tags': ['test', 'one', 'two'],
                'ranges': [
                    {'start': '//div[@id="fnstr.idm320760248608"]/span[1]',
                     'end': '//div[@id="fnstr.idm320760242176"]/span[1]',
                     'startOffset': 0,
                     'endOffset': 6
                     }
                ],
                'ark': page_uri
                }),
            user=user)
        note.save()
        imagenote = Annotation(text='interesting image detail', uri=page_uri,
            user=user,
            extra_data=json.dumps({
                'image_selection': {
                    # NOTE: image src currently not checked when generating annotated tei
                    'h': '20.73%',
                    'w': '14.70%',
                    'y': '62.42%',
                    'x': '61.60%'
                    },
                'ark': page_uri
                })
            )
        imagenote.save()

        # use page tei fixture as starting point
        title = 'Lecoq'
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR, 'teifacsimile.xml'),
            tei.AnnotatedFacsimile)
        teidoc.title = title
        teidoc.page.href = page_uri
        del teidoc.responsible_names[0]  # remove empty resp name from fixture

        annotei = annotated_tei(teidoc, Annotation.objects.all())
        self.assert_(isinstance(annotei, tei.AnnotatedFacsimile),
            'annotated_tei should return an insance of tei.AnnotatedFacsimile')

        # title should be updated, split into main and subtitle parts
        self.assertEqual(title, annotei.main_title)
        self.assertEqual(', an annotated digital edition', annotei.subtitle)
        self.assertEqual('annotated by', annotei.responsibility)
        # annotation authors should be added in resp statement
        self.assertEqual(user.username, annotei.responsible_names[0].id)
        self.assertEqual(user.get_full_name(), annotei.responsible_names[0].value)

        # publication statement should include readux version, current date
        self.assert_('Annotated TEI generated by Readux' in annotei.pubstmt.desc)
        self.assert_(__version__ in annotei.pubstmt.desc)
        today = datetime.date.today()
        self.assertEqual(today, annotei.pubstmt.date)
        self.assertEqual(today, annotei.pubstmt.date_normal)

        # tei annotation should be added to body for text note
        self.assertEqual('annotation-%s' % note.id, annotei.annotations[0].id)
        # start/end highlight anchors should be added to facsimile
        self.assert_(annotei.node.xpath('//tei:anchor[@xml:id="highlight-start-%s"]' % note.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))
        self.assert_(annotei.node.xpath('//tei:anchor[@xml:id="highlight-end-%s"]' % note.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))

        # tei annotation should be added to body for image note
        self.assertEqual('annotation-%s' % imagenote.id, annotei.annotations[1].id)
        # zone added for image highlight
        self.assert_(annotei.node.xpath('//tei:zone[@xml:id="highlight-%s"][@type="image-annotation-highlight"]' % imagenote.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))

        # tags added to back as interp group
        self.assertEqual('test', annotei.tags.interp[0].id)
        self.assertEqual('test', annotei.tags.interp[0].value)

        # encoding desc should be present
        self.assert_(annotei.encoding_desc)
コード例 #24
0
ファイル: annotate.py プロジェクト: saracarl/readux
class AnnotatedTei(TestCase):

    def test_annotation_to_tei(self):
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR, 'teifacsimile.xml'),
            tei.AnnotatedFacsimile)

        note = Annotation(text="Here's the thing", quote="really",
            extra_data=json.dumps({'sample data': 'foobar',
                'tags': ['test', 'one', 'two']}))

        teinote = annotation_to_tei(note, teidoc)
        self.assert_(isinstance(teinote, tei.Note))
        self.assertEqual('annotation-%s' % note.id, teinote.id)
        self.assert_(teinote.href.endswith(note.get_absolute_url()))
        self.assertEqual(note.text, teinote.paragraphs[0])

        # todo: add a schema validation once we get the output to be valid
        # teidoc.schema_valid()
        # access errors with teidoc.schema_validation_errors()

        # annotation user should be set as note response
        user = get_user_model()(username='******')
        user.save()
        note.user = user
        teinote = annotation_to_tei(note, teidoc)
        self.assertEqual(user.username, teinote.resp)

        # tags should be set as interp ids ana attribute
        for tag in note.info()['tags']:
            self.assert_('#%s' % tag in teinote.ana)

        # test that markdown formatting is coming through
        footnote = '''Footnotes[^1] have a label and content.

[^1]: This is some footnote content.'''
        note.text = footnote
        teinote = annotation_to_tei(note, teidoc)
        self.assert_('<ref target="#fn1" type="noteAnchor">1</ref>' in
            teinote.serialize())

        # markdown should be included in a code element
        self.assertEqual(note.text, teinote.markdown)

        # related page references
        rel_pages = [
            'http://testpid.co/ark:/1234/11',
            'http://testpid.co/ark:/1234/22',
            'http://testpid.co/ark:/1234/qq'
        ]
        note.extra_data = json.dumps({'related_pages': rel_pages})
        teinote = annotation_to_tei(note, teidoc)
        self.assertEqual(len(rel_pages), len(teinote.related_pages))
        # first ark has a corresponding id in the fixture, should be converted
        self.assertEqual('#%s' % teidoc.page_id_by_xlink(rel_pages[0]),
            teinote.related_pages[0].target)
        for idx in range(len(rel_pages)):
            self.assertEqual(rel_pages[idx], teinote.related_pages[idx].text)


    zotero_note = Annotation(text=u'''update test ing la lala ([Jockers and Mimno 2013](#zotero-MUXAEE89))
more content ([Underwood and Sellers 2012](#zotero-7CBCH6E8))
la la la foo bar lala
---
### Works Cited
* <a name="zotero-MUXAEE89"></a>Jockers, Matthew L., and David Mimno. “Significant Themes in 19th-Century Literature.” <i>Poetics</i> 41, no. 6 (December 2013): 750–69. doi:10.1016/j.poetic.2013.08.005.
* <a name="zotero-7CBCH6E8"></a>Underwood, Ted, and Jordan Sellers. “The Emergence of Literary Diction.” <i>Journal of Digital Humanities</i>, June 26, 2012. http://journalofdigitalhumanities.org/1-2/the-emergence-of-literary-diction-by-ted-underwood-and-jordan-sellers/.''',
            quote="really",
            extra_data=json.dumps({'citations': [
    '<biblStruct xmlns="http://www.tei-c.org/ns/1.0" type="webpage" xml:id="zoteroItem-http://zotero.org/users/758030/items/7CBCH6E8" corresp="http://zotero.org/users/758030/items/7CBCH6E8"><monogr><title level="m">The Emergence of Literary Diction</title><author><forename>Ted</forename><surname>Underwood</surname></author><author><forename>Jordan</forename><surname>Sellers</surname></author><imprint><date>2012</date><note type="accessed">2015-05-09T22:02:51Z</note><note type="url">http://journalofdigitalhumanities.org/1-2/the-emergence-of-literary-diction-by-ted-underwood-and-jordan-sellers/</note></imprint></monogr></biblStruct>',
    '<biblStruct xmlns="http://www.tei-c.org/ns/1.0" type="journalArticle" xml:id="zoteroItem-http://zotero.org/users/758030/items/MUXAEE89" corresp="http://zotero.org/users/758030/items/MUXAEE89"><analytic><title level="a">Significant themes in 19th-century literature</title><author><forename>Matthew L.</forename><surname>Jockers</surname></author><author><forename>David</forename><surname>Mimno</surname></author></analytic><monogr><title level="j">Poetics</title><imprint><biblScope unit="volume">41</biblScope><biblScope unit="issue">6</biblScope><biblScope unit="page">750-769</biblScope><date>2013</date><note type="accessed">2016-01-24T02:44:56Z</note><note type="url">http://linkinghub.elsevier.com/retrieve/pii/S0304422X13000673</note></imprint></monogr><idno type="ISSN">0304422X</idno><idno type="DOI">10.1016/j.poetic.2013.08.005</idno></biblStruct>'
    ]}))
    def test_annotation_citation_to_tei(self):
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR, 'teifacsimile.xml'),
            tei.AnnotatedFacsimile)

        teinote = annotation_to_tei(self.zotero_note, teidoc)
        # print teinote.serialize(pretty=True)
        # number of citations should match
        self.assertEqual(len(self.zotero_note.extra_data['citations']),
                         len(teinote.citations))
        # minimal inspection to check that values carried through as expected
        self.assertEqual('webpage', teinote.citations[0].type)
        self.assertEqual('journalArticle', teinote.citations[1].type)

        self.assertEqual('zotero-7CBCH6E8', teinote.citations[0].id)
        self.assertEqual('zotero-MUXAEE89', teinote.citations[1].id)


    def test_insert_anchor(self):
        def get_test_elements():
            div = etree.fromstring('''<div>
                <p>Sample text to insert anchors into</p>
            </div>''')
            element = div.xpath('//p')[0]
            return div, element

        div, element = get_test_elements()
        anchor = etree.fromstring('<anchor/>')
        # insert anchor at 0 index relative to paragraph
        insert_anchor(element, anchor, 0)

        # 0 index, anchor should be *before* tag
        self.assertEqual('anchor', element.getprevious().tag)

        div, element = get_test_elements()
        # insert anchor in the middle of the paragraph
        insert_anchor(element, anchor, 11)
        # anchor element should be a child of p tag
        self.assert_(anchor in element.getchildren())
        # text should be split before and after anchor
        self.assertEqual('Sample text', element.text)
        self.assertEqual(' to insert anchors into', anchor.tail)

        div, element = get_test_elements()
        anchor = etree.fromstring('<anchor/>')
        # insert anchor at the end of the paragraph
        insert_anchor(element, anchor, 35)
        # 0 index, anchor should be after tag
        self.assertEqual('anchor', element.getnext().tag)

    def test_annotated_tei(self):
        # create annotation with a user
        user = get_user_model()(username='******',
            first_name="Anne", last_name="O'Tater")
        user.save()
        page_uri = "http://readux.co/books/pages/some:1/"
        note = Annotation(text="Here's the thing", quote="really",
            uri=page_uri,
            extra_data=json.dumps({
                'sample data': 'foobar',
                'tags': ['test', 'one', 'two'],
                'ranges': [
                    {'start': '//div[@id="fnstr.idm320760248608"]/span[1]',
                     'end': '//div[@id="fnstr.idm320760242176"]/span[1]',
                     'startOffset': 0,
                     'endOffset': 6
                     }
                ],
                'ark': page_uri
                }),
            user=user)
        note.save()
        imagenote = Annotation(text='interesting image detail', uri=page_uri,
            user=user,
            extra_data=json.dumps({
                'image_selection': {
                    # NOTE: image src currently not checked when generating annotated tei
                    'h': '20.73%',
                    'w': '14.70%',
                    'y': '62.42%',
                    'x': '61.60%'
                    },
                'ark': page_uri
                })
            )
        imagenote.save()

        # use page tei fixture as starting point
        title = 'Lecoq'
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR, 'teifacsimile.xml'),
            tei.AnnotatedFacsimile)
        teidoc.title = title
        teidoc.page.href = page_uri
        del teidoc.responsible_names[0]  # remove empty resp name from fixture

        annotei = annotated_tei(teidoc, Annotation.objects.all())
        self.assert_(isinstance(annotei, tei.AnnotatedFacsimile),
            'annotated_tei should return an insance of tei.AnnotatedFacsimile')

        # title should be updated, split into main and subtitle parts
        self.assertEqual(title, annotei.main_title)
        self.assertEqual(', an annotated digital edition', annotei.subtitle)
        self.assertEqual('annotated by', annotei.responsibility)
        # annotation authors should be added in resp statement
        self.assertEqual(user.username, annotei.responsible_names[0].id)
        self.assertEqual(user.get_full_name(), annotei.responsible_names[0].value)

        # publication statement should include readux version, current date
        self.assert_('Annotated TEI generated by Readux' in annotei.pubstmt.desc)
        self.assert_(__version__ in annotei.pubstmt.desc)
        today = datetime.date.today()
        self.assertEqual(today, annotei.pubstmt.date)
        self.assertEqual(today, annotei.pubstmt.date_normal)

        # tei annotation should be added to body for text note
        self.assertEqual('annotation-%s' % note.id, annotei.annotations[0].id)
        # start/end highlight anchors should be added to facsimile
        self.assert_(annotei.node.xpath('//tei:anchor[@xml:id="highlight-start-%s"]' % note.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))
        self.assert_(annotei.node.xpath('//tei:anchor[@xml:id="highlight-end-%s"]' % note.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))

        # tei annotation should be added to body for image note
        self.assertEqual('annotation-%s' % imagenote.id, annotei.annotations[1].id)
        # zone added for image highlight
        self.assert_(annotei.node.xpath('//tei:zone[@xml:id="highlight-%s"][@type="image-annotation-highlight"]' % imagenote.id,
            namespaces=tei.Zone.ROOT_NAMESPACES))

        # tags added to back as interp group
        self.assertEqual('test', annotei.tags.interp[0].id)
        self.assertEqual('test', annotei.tags.interp[0].value)

        # encoding desc should be present
        self.assert_(annotei.encoding_desc)

    def test_consolidate_bibl(self):
        teidoc = load_xmlobject_from_file(os.path.join(FIXTURE_DIR,
                                                       'teifacsimile.xml'),
                                          tei.AnnotatedFacsimile)
        teinote = annotation_to_tei(self.zotero_note, teidoc)
        teidoc.annotations.append(teinote)
        consolidate_bibliography(teidoc)

        self.assertEqual(2, len(teidoc.citations),
            'annotation citations should be present in main document bibl')
        teinote = teidoc.annotations[0]
        self.assertEqual(0, len(teinote.citations),
            'citations should not be present on individual annotation')
        self.assertEqual(None, teinote.works_cited)
        self.assertEqual(None, teinote.zotero_items)
        self.assertEqual(None, teinote.works_cited_milestone)
        teinote_xml = teinote.serialize()
        self.assertFalse('<item><anchor xml:id="zotero-' in teinote_xml)
        self.assertFalse('<listBibl/>' in teinote_xml)

        # repeated zotero ids should only appear once in document bibl
        # load the same note and add it again
        teinote = annotation_to_tei(self.zotero_note, teidoc)
        teidoc.annotations.append(teinote)
        consolidate_bibliography(teidoc)
        self.assertEqual(2, len(teidoc.citations),
            'citations repeated in annotations should only appear once')