def test_rotate_note(self):
     """Test rotating the page with a note"""
     document = DocumentFactory(page_count=3)
     note = NoteFactory.create(document=document, page_number=1)
     x1, x2, y1, y2 = note.x1, note.x2, note.y1, note.y2
     assert None not in (x1, x2, y1, y2)
     modifications = [
         {
             "page_spec": [[0, 2]],
             "modifications": [{"type": "rotate", "angle": "cc"}],
         }
     ]
     send_post_process(document, modifications)
     # still one note
     assert document.notes.count() == 1
     note.refresh_from_db()
     # not moved
     assert note.page_number == 1
     # but is rotated
     assert (
         note.x1 == (1 - y2)
         and note.x2 == (1 - y1)
         and note.y1 == x1
         and note.y2 == x2
     )
     document.refresh_from_db()
     assert document.page_count == 3
Beispiel #2
0
 def test_update_bulk(self, client, user, mocker):
     """Test replacing the document set in a project"""
     mock_solr_index = mocker.patch(
         "documentcloud.projects.views.solr_index")
     old_documents = DocumentFactory.create_batch(5, user=user)
     new_documents = old_documents[:2] + DocumentFactory.create_batch(
         3, user=user)
     project = ProjectFactory(user=user, documents=old_documents)
     other_project = ProjectFactory(user=user, documents=old_documents)
     client.force_authenticate(user=user)
     response = client.put(
         f"/api/projects/{project.pk}/documents/",
         [{
             "document": d.pk
         } for d in new_documents],
         format="json",
     )
     assert response.status_code == status.HTTP_200_OK
     assert {d.pk
             for d in new_documents
             } == {d.pk
                   for d in project.documents.all()}
     assert {d.pk
             for d in old_documents
             } == {d.pk
                   for d in other_project.documents.all()}
     # check that the solr index was properly updated for all documents
     run_commit_hooks()
     calls = []
     for update in old_documents[:2]:
         calls.append(
             mocker.call(
                 update.pk,
                 field_updates={
                     "projects": "set",
                     "projects_edit_access": "set"
                 },
             ))
     for add in new_documents[2:]:
         calls.append(
             mocker.call(
                 add.pk,
                 field_updates={
                     "projects": "set",
                     "projects_edit_access": "set"
                 },
             ))
     for delete in old_documents[2:]:
         calls.append(
             mocker.call(
                 delete.pk,
                 field_updates={
                     "projects": "set",
                     "projects_edit_access": "set"
                 },
             ))
     mock_solr_index.delay.assert_has_calls(calls, any_order=True)
Beispiel #3
0
 def test_list_bad(self, client):
     """List documents in a project including some you cannot view"""
     size = 10
     documents = DocumentFactory.create_batch(size, access=Access.public)
     documents.extend(
         DocumentFactory.create_batch(size, access=Access.private))
     project = ProjectFactory(documents=documents)
     response = client.get(f"/api/projects/{project.pk}/documents/")
     assert response.status_code == status.HTTP_200_OK
     response_json = json.loads(response.content)
     assert len(response_json["results"]) == size
 def test_remove_section(self):
     """Test removing the page with a section"""
     document = DocumentFactory(page_count=3)
     section = SectionFactory.create(document=document, page_number=1)
     modifications = [{"page_spec": [0, 2]}]
     send_post_process(document, modifications)
     # the section is deleted
     assert document.sections.count() == 0
     with pytest.raises(Section.DoesNotExist):
         section.refresh_from_db()
     document.refresh_from_db()
     assert document.page_count == 2
 def test_simple(
     self, factory, attr, page_spec, initial_page, final_page, count, page_count
 ):
     """Test simple modifications"""
     document = DocumentFactory(page_count=3)
     obj = factory.create(document=document, page_number=initial_page)
     modifications = [{"page_spec": page_spec}]
     send_post_process(document, modifications)
     assert getattr(document, attr).count() == count
     obj.refresh_from_db()
     assert obj.page_number == final_page
     document.refresh_from_db()
     assert document.page_count == page_count
Beispiel #6
0
 def test_list_permissions(self, client):
     """List users you can view"""
     # the current user, a user in the same organization, a user in the same
     # project, a user with a public document, a user with a private document
     users = UserFactory.create_batch(5)
     OrganizationFactory(members=users[:2])
     ProjectFactory(user=users[0], collaborators=[users[2]])
     DocumentFactory(user=users[3], access=Access.public)
     DocumentFactory(user=users[4], access=Access.private)
     client.force_authenticate(user=users[0])
     response = client.get("/api/users/")
     assert response.status_code == status.HTTP_200_OK
     response_json = json.loads(response.content)
     # you can see all users except for the user with a private document
     assert len(response_json["results"]) == 4
 def test_remove_note(self):
     """Test removing the page with a note"""
     document = DocumentFactory(page_count=3)
     note = NoteFactory.create(document=document, page_number=1)
     modifications = [{"page_spec": [0, 2]}]
     send_post_process(document, modifications)
     # the note is moved to the first page as a page note
     assert document.notes.count() == 1
     note.refresh_from_db()
     # moved to the first page
     assert note.page_number == 0
     # as a full page note
     assert note.x1 is None
     document.refresh_from_db()
     assert document.page_count == 2
Beispiel #8
0
 def test_partial_update_bulk_bad_missing(self, client, user):
     """Test updating multiple documents in a project"""
     documents = DocumentFactory.create_batch(5, user=user)
     other_document = DocumentFactory(user=user)
     project = ProjectFactory(user=user, documents=documents)
     client.force_authenticate(user=user)
     response = client.patch(
         f"/api/projects/{project.pk}/documents/",
         [{
             "document": other_document.pk,
             "edit_access": True
         }],
         format="json",
     )
     assert response.status_code == status.HTTP_400_BAD_REQUEST
 def test_other_doc_id(self):
     long_doc = DocumentFactory(page_count=100)
     serializer = self.get_modification_serializer([{
         "page": "0-49",
         "id": long_doc.pk
     }], 10)
     assert serializer.is_valid()
 def test_other_doc_id_too_short(self):
     short_doc = DocumentFactory(page_count=20)
     serializer = self.get_modification_serializer([{
         "page": "0-49",
         "id": short_doc.pk
     }], 100)
     assert not serializer.is_valid()
 def test_rotate_note_and_copy(self):
     """Test rotating the page with a note
     Ensure copied note is not double rotated
     """
     document = DocumentFactory(page_count=3)
     note = NoteFactory.create(document=document, page_number=1)
     x1, x2, y1, y2 = note.x1, note.x2, note.y1, note.y2
     assert None not in (x1, x2, y1, y2)
     modifications = [
         {
             "page_spec": [1, 1, 1],
             "modifications": [{"type": "rotate", "angle": "cc"}],
         }
     ]
     send_post_process(document, modifications)
     # two notes
     assert document.notes.count() == 3
     notes = document.notes.all()
     for note in notes:
         # all notes should be rotated the same way
         assert (
             note.x1 == (1 - y2)
             and note.x2 == (1 - y1)
             and note.y1 == x1
             and note.y2 == x2
         )
 def test_section_delete_and_move(self):
     """Test deleting and moving sections obeys unique constraint
     This can be avoided by deleting, then updating, then creating
     """
     document = DocumentFactory(page_count=3)
     section1 = SectionFactory.create(document=document, page_number=1)
     section2 = SectionFactory.create(document=document, page_number=2)
     modifications = [{"page_spec": [2, 2, 2]}]
     send_post_process(document, modifications)
     assert document.sections.count() == 3
     with pytest.raises(Section.DoesNotExist):
         section1.refresh_from_db()
     section2.refresh_from_db()
     assert section2.page_number == 0
     document.refresh_from_db()
     assert document.page_count == 3
Beispiel #13
0
 def test_retrieve_bad(self, client):
     """Test retrieving a document from project"""
     document = DocumentFactory(access=Access.private)
     project = ProjectFactory(documents=[document])
     response = client.get(
         f"/api/projects/{project.pk}/documents/{document.pk}/")
     assert response.status_code == status.HTTP_404_NOT_FOUND
Beispiel #14
0
 def test_list(self, client):
     """List documents in a project"""
     size = 10
     project = ProjectFactory(documents=DocumentFactory.create_batch(size))
     response = client.get(f"/api/projects/{project.pk}/documents/")
     assert response.status_code == status.HTTP_200_OK
     response_json = json.loads(response.content)
     assert len(response_json["results"]) == size
Beispiel #15
0
 def test_create_bulk(self, client, project):
     """Add multiple documents to a project"""
     # one the document you own should be added with edit access
     # the other one should not
     documents = [DocumentFactory(user=project.user), DocumentFactory()]
     client.force_authenticate(user=project.user)
     response = client.post(
         f"/api/projects/{project.pk}/documents/",
         [{
             "document": d.pk
         } for d in documents],
         format="json",
     )
     assert response.status_code == status.HTTP_201_CREATED
     assert (project.documents.filter(
         projectmembership__edit_access=True).first() == documents[0])
     assert (project.documents.filter(
         projectmembership__edit_access=False).first() == documents[1])
 def test_rotate_section(self):
     """Test rotating the page with a section"""
     document = DocumentFactory(page_count=3)
     section = SectionFactory.create(document=document, page_number=1)
     modifications = [
         {
             "page_spec": [[0, 2]],
             "modifications": [{"type": "rotate", "angle": "ccw"}],
         }
     ]
     send_post_process(document, modifications)
     # still one section
     assert document.sections.count() == 1
     section.refresh_from_db()
     # not moved
     assert section.page_number == 1
     document.refresh_from_db()
     assert document.page_count == 3
Beispiel #17
0
 def test_destroy_bulk_bad(self, client, user):
     """Test removing a document from a project you do not have permission to"""
     documents = DocumentFactory.create_batch(3, user=user)
     project = ProjectFactory(documents=documents)
     client.force_authenticate(user=user)
     doc_ids = ",".join(str(d.pk) for d in documents)
     response = client.delete(
         f"/api/projects/{project.pk}/documents/?document_id__in={doc_ids}")
     assert response.status_code == status.HTTP_403_FORBIDDEN
Beispiel #18
0
 def test_destroy_bulk(self, client, user):
     """Test removing a document from a project"""
     documents = DocumentFactory.create_batch(3, user=user)
     project = ProjectFactory(user=user, documents=documents)
     client.force_authenticate(user=user)
     doc_ids = ",".join(str(d.pk) for d in documents[:2])
     response = client.delete(
         f"/api/projects/{project.pk}/documents/?document_id__in={doc_ids}")
     assert response.status_code == status.HTTP_204_NO_CONTENT
     assert project.documents.count() == 1
Beispiel #19
0
 def test_update_bad_document(self, client):
     """You may not try to change the document ID"""
     documents = DocumentFactory.create_batch(2)
     project = ProjectFactory(user=documents[0].user,
                              documents=[documents[0]])
     client.force_authenticate(user=project.user)
     response = client.patch(
         f"/api/projects/{project.pk}/documents/{documents[0].pk}/",
         {"document": documents[1].pk},
     )
     assert response.status_code == status.HTTP_400_BAD_REQUEST
Beispiel #20
0
 def test_create_implicit_edit(self, client, project):
     """Add a document to a project with edit access"""
     document = DocumentFactory(user=project.user)
     client.force_authenticate(user=project.user)
     response = client.post(
         f"/api/projects/{project.pk}/documents/",
         {"document": document.pk},
         format="json",
     )
     assert response.status_code == status.HTTP_201_CREATED
     assert project.projectmembership_set.filter(document=document,
                                                 edit_access=True).exists()
 def test_import(self, factory, attr):
     """Test importing a page with a note"""
     document = DocumentFactory(page_count=3)
     import_document = DocumentFactory(page_count=1)
     obj = factory.create(document=import_document, page_number=0)
     modifications = [
         {"page_spec": [[0, 2]]},
         {"id": import_document.pk, "page_spec": [0]},
     ]
     send_post_process(document, modifications)
     # both document and import document have one obj now
     assert getattr(document, attr).count() == 1
     assert getattr(import_document, attr).count() == 1
     obj.refresh_from_db()
     # not moved
     assert obj.page_number == 0
     assert obj.document == import_document
     # new obj
     new_obj = getattr(document, attr).first()
     assert new_obj.page_number == 3
     assert new_obj.document == document
     document.refresh_from_db()
     assert document.page_count == 4
Beispiel #22
0
    def test_list_queries(self, client, expand):
        """Queries should be constant"""
        small_size = 1
        documents = DocumentFactory.create_batch(small_size)
        projects = ProjectFactory.create_batch(small_size, documents=documents)
        for document in documents:
            NoteFactory.create_batch(small_size, document=document)
            SectionFactory.create_batch(small_size, document=document)
        reset_queries()
        client.get(
            f"/api/projects/{projects[0].pk}/documents/?expand={expand}")
        num_queries = len(connection.queries)

        size = 10
        documents = DocumentFactory.create_batch(size)
        projects = ProjectFactory.create_batch(size, documents=documents)
        for document in documents:
            NoteFactory.create_batch(size, document=document)
            SectionFactory.create_batch(size, document=document)
        reset_queries()
        response = client.get(
            f"/api/projects/{projects[0].pk}/documents/?expand={expand}")
        assert num_queries == len(connection.queries)
        assert len(response.json()["results"]) == size
    def get_modification_serializer(self, data, page_count):
        document = DocumentFactory(page_count=page_count)

        # Mock the view and request
        mock_request = MagicMock()
        mock_request.user.has_perm = lambda _perm, _doc: True

        mock_view = MagicMock()
        mock_view.kwargs = {"document_pk": document.pk}
        mock_view.context = {"request": mock_request}

        return ModificationSpecSerializer(data={"data": data},
                                          context={
                                              "view": mock_view,
                                              "request": mock_request
                                          })
Beispiel #24
0
 def test_partial_update_bulk(self, client, user):
     """Test updating multiple documents in a project"""
     documents = DocumentFactory.create_batch(5, user=user)
     project = ProjectFactory(user=user, documents=documents)
     client.force_authenticate(user=user)
     response = client.patch(
         f"/api/projects/{project.pk}/documents/",
         [{
             "document": d.pk,
             "edit_access": True
         } for d in documents[:2]],
         format="json",
     )
     assert response.status_code == status.HTTP_200_OK
     assert project.projectmembership_set.filter(
         edit_access=True).count() == 2
     assert project.projectmembership_set.count() == 5
Beispiel #25
0
def document():
    return DocumentFactory()
Beispiel #26
0
def setup_solr(django_db_setup, django_db_blocker):
    """Set up the models for the search tests

    `django_db_setup` causes pytest to initiate the test database
    """
    # pylint: disable=unused-argument
    solr = pysolr.Solr(settings.SOLR_URL, auth=settings.SOLR_AUTH)
    with django_db_blocker.unblock():
        try:
            organizations = {}
            users = {}
            documents = {}
            notes = {}
            # this enables searching through notes for users in that org
            entitlement = OrganizationEntitlementFactory()
            for org in ORGANIZATIONS:
                if org.pop("entitlement", None) == "org":
                    org["entitlement"] = entitlement
                organizations[org["id"]] = OrganizationFactory(**org)
            for user in USERS:
                user = user.copy()
                org = user.pop("organization")
                users[user["id"]] = UserFactory(
                    membership__organization=organizations[org], **user)
            for doc in DOCUMENTS:
                doc = doc.copy()
                user = doc.pop("user")
                org = doc.pop("organization")
                documents[doc["id"]] = DocumentFactory(
                    user=users[user], organization=organizations[org], **doc)
            for note in NOTES:
                note = note.copy()
                user = note.pop("user")
                org = note.pop("organization")
                doc = note.pop("document")
                notes[note["id"]] = NoteFactory(
                    user=users[user],
                    organization=organizations[org],
                    document=documents[doc],
                    **note,
                )
            for proj in PROJECTS:
                ProjectFactory(
                    id=proj["id"],
                    title=proj["title"],
                    user=users[proj["user"]],
                    edit_documents=[documents[d] for d in proj["documents"]],
                    collaborators=[users[a] for a in proj["collaborators"]],
                    edit_collaborators=[
                        users[a] for a in proj["edit_collaborators"]
                    ],
                )
            for doc in documents.values():
                solr.add([doc.solr()])
            solr.commit()
            yield
        finally:
            Document.objects.all().delete()
            Project.objects.all().delete()
            User.objects.all().delete()
            Organization.objects.all().delete()
            solr.delete(q="*:*")
Beispiel #27
0
def test_document_rules():
    # pylint: disable=too-many-locals
    anonymous = AnonymousUser()
    owner = UserFactory()
    edit_collaborator = UserFactory()
    view_collaborator = UserFactory()
    no_access_collaborator = UserFactory()
    organization_member = UserFactory()

    organization = OrganizationFactory(members=[owner, organization_member])
    organization_member.organization = organization

    public_document = DocumentFactory(user=owner,
                                      organization=organization,
                                      access=Access.public,
                                      title="public")
    public_pending_document = DocumentFactory(
        user=owner,
        organization=organization,
        access=Access.public,
        status=Status.pending,
        title="pending",
    )
    organization_document = DocumentFactory(user=owner,
                                            organization=organization,
                                            access=Access.organization,
                                            title="org")
    private_document = DocumentFactory(user=owner,
                                       organization=organization,
                                       access=Access.private,
                                       title="private")
    invisible_document = DocumentFactory(
        user=owner,
        organization=organization,
        access=Access.invisible,
        title="invisible",
    )
    documents = [
        public_document,
        public_pending_document,
        private_document,
        organization_document,
        invisible_document,
    ]

    ProjectFactory(edit_collaborators=[edit_collaborator],
                   edit_documents=documents)
    ProjectFactory(collaborators=[view_collaborator], edit_documents=documents)
    ProjectFactory(collaborators=[no_access_collaborator], documents=documents)

    for user, document, can_view, can_change, can_share in [
        (anonymous, public_document, True, False, False),
        (anonymous, public_pending_document, False, False, False),
        (anonymous, organization_document, False, False, False),
        (anonymous, private_document, False, False, False),
        (anonymous, invisible_document, False, False, False),
        (owner, public_document, True, True, True),
        (owner, public_pending_document, True, True, True),
        (owner, organization_document, True, True, True),
        (owner, private_document, True, True, True),
        (owner, invisible_document, False, False, False),
        (edit_collaborator, public_document, True, False, False),
        (edit_collaborator, public_pending_document, True, False, False),
        (edit_collaborator, organization_document, True, True, False),
        (edit_collaborator, private_document, True, True, False),
        (edit_collaborator, invisible_document, False, False, False),
        (view_collaborator, public_document, True, False, False),
        (view_collaborator, public_pending_document, True, False, False),
        (view_collaborator, organization_document, True, False, False),
        (view_collaborator, private_document, True, False, False),
        (view_collaborator, invisible_document, False, False, False),
        (no_access_collaborator, public_document, True, False, False),
        (no_access_collaborator, public_pending_document, False, False, False),
        (no_access_collaborator, organization_document, False, False, False),
        (no_access_collaborator, private_document, False, False, False),
        (no_access_collaborator, invisible_document, False, False, False),
        (organization_member, public_document, True, True, True),
        (organization_member, public_pending_document, True, True, True),
        (organization_member, organization_document, True, True, True),
        (organization_member, private_document, False, False, False),
        (organization_member, invisible_document, False, False, False),
    ]:
        assert (user.has_perm("documents.view_document", document) is
                can_view), f"{user.get_full_name()} - {document.title}"
        assert (user.has_perm("documents.change_document", document) is
                can_change), f"{user.get_full_name()} - {document.title}"
        assert (user.has_perm("documents.share_document", document) is
                can_share), f"{user.get_full_name()} - {document.title}"
        assert (user.has_perm("documents.delete_document", document) is
                can_share), f"{user.get_full_name()} - {document.title}"
Beispiel #28
0
def test_store_statistics():
    documents = []
    doc_data = [
        (Access.public, 10, 10),
        (Access.organization, 20, 20),
        (Access.private, 30, 30),
        (Access.invisible, 1, 40),
    ]
    for access, num, page_count in doc_data:
        documents.extend(
            DocumentFactory.create_batch(num, access=access, page_count=page_count)
        )
    # to test user / org uniqueness count
    documents[1].user = documents[0].user
    documents[1].organization = documents[0].organization
    documents[1].save()
    documents[2].organization = documents[0].organization
    documents[2].save()
    note_data = [
        (Access.public, 35),
        (Access.organization, 25),
        (Access.private, 15),
        (Access.invisible, 0),
    ]
    for access, num in note_data:
        NoteFactory.create_batch(num, access=access, document=documents[0])
    num_projects = 42
    ProjectFactory.create_batch(num_projects)
    store_statistics()
    stats = Statistics.objects.first()
    assert stats.date == date.today() - timedelta(1)

    assert stats.total_documents == sum(d[1] for d in doc_data)
    assert stats.total_documents_public == doc_data[0][1]
    assert stats.total_documents_organization == doc_data[1][1]
    assert stats.total_documents_private == doc_data[2][1]
    assert stats.total_documents_invisible == doc_data[3][1]

    assert stats.total_pages == sum(d[1] * d[2] for d in doc_data)
    assert stats.total_pages_public == doc_data[0][1] * doc_data[0][2]
    assert stats.total_pages_organization == doc_data[1][1] * doc_data[1][2]
    assert stats.total_pages_private == doc_data[2][1] * doc_data[2][2]
    assert stats.total_pages_invisible == doc_data[3][1] * doc_data[3][2]

    assert stats.total_notes == sum(n[1] for n in note_data)
    assert stats.total_notes_public == note_data[0][1]
    assert stats.total_notes_organization == note_data[1][1]
    assert stats.total_notes_private == note_data[2][1]
    assert stats.total_notes_invisible == note_data[3][1]

    assert stats.total_projects == num_projects

    # one repeat user on public documents
    assert stats.total_users_uploaded == sum(d[1] for d in doc_data) - 1
    assert stats.total_users_public_uploaded == doc_data[0][1] - 1
    assert stats.total_users_organization_uploaded == doc_data[1][1]
    assert stats.total_users_private_uploaded == doc_data[2][1]

    # two repeat organizations on public documents
    assert stats.total_organizations_uploaded == sum(d[1] for d in doc_data) - 2
    assert stats.total_organizations_public_uploaded == doc_data[0][1] - 2
    assert stats.total_organizations_organization_uploaded == doc_data[1][1]
    assert stats.total_organizations_private_uploaded == doc_data[2][1]