Пример #1
0
def test_scheduled_tasks(app, mocker):
    """Test scheduled tasks."""
    org = app.data["org"]
    task = Task.create(org=org, task_type=TaskType.AFFILIATION)
    rq = app.extensions["rq2"]
    s = rq.get_scheduler()
    s.run(burst=True)
    task = Task.get(task.id)
    utils.process_tasks.queue()
    task = Task.get(task.id)
    assert task.expires_at is not None
    task.expires_at = utils.datetime(1988, 1, 1)
    task.save()
    utils.process_tasks.queue()
    assert Task.select().where(Task.id == task.id).count() == 0

    Organisation.update(webhook_enabled=True,
                        email_notifications_enabled=True).execute()
    User.update(orcid_updated_at=utils.date.today().replace(day=1) -
                utils.timedelta(days=1)).execute()
    send_email = mocker.patch("orcid_hub.utils.send_email")
    utils.send_orcid_update_summary.queue(org_id=org.id)
    send_email.assert_called()
Пример #2
0
def models(testdb):

    Organisation.insert_many((dict(name="Organisation #%d" % i,
                                   tuakiri_name="Organisation #%d" % i,
                                   orcid_client_id="client-%d" % i,
                                   orcid_secret="secret-%d" % i,
                                   confirmed=(i % 2 == 0))
                              for i in range(10))).execute()

    User.insert_many(
        (dict(name="Test User #%d" % i,
              first_name="Test_%d" % i,
              last_name="User_%d" % i,
              email="user%d@org%d.org.nz" % (i, i * 4 % 10),
              confirmed=(i % 3 != 0),
              roles=Role.SUPERUSER if i % 42 == 0 else Role.ADMIN if i %
              13 == 0 else Role.RESEARCHER) for i in range(60))).execute()

    User.insert_many((dict(name="Test User with ORCID ID 'ABC-123' #%d" % i,
                           orcid="ABC-123",
                           first_name="Test_%d" % i,
                           last_name="User_%d" % i,
                           email="user_the_same_id_%d@org%d.org.nz" % (i, i),
                           confirmed=True,
                           organisation=(i + 1),
                           roles=Role.RESEARCHER)
                      for i in range(3))).execute()

    UserOrg.insert_many(
        dict(user=u.id, org=u.organisation_id)
        for u in User.select().where(User.orcid == "ABC-123")).execute()

    UserOrg.insert_many(
        (dict(is_admin=((u + o) % 23 == 0), user=u, org=o)
         for (u, o) in product(range(2, 60, 4), range(2, 10)))).execute()

    UserOrg.insert_many(
        (dict(is_admin=True, user=43, org=o) for o in range(1, 11))).execute()

    OrcidToken.insert_many((dict(user=User.get(id=1),
                                 org=Organisation.get(id=1),
                                 scopes="/read-limited",
                                 access_token="Test_%d" % i)
                            for i in range(60))).execute()

    UserOrgAffiliation.insert_many((dict(user=User.get(id=1),
                                         organisation=Organisation.get(id=1),
                                         department_name="Test_%d" % i,
                                         department_city="Test_%d" % i,
                                         role_title="Test_%d" % i,
                                         path="Test_%d" % i,
                                         put_code="%d" % i)
                                    for i in range(30))).execute()

    Task.insert_many((dict(org=Organisation.get(id=1),
                           created_by=User.get(id=1),
                           updated_by=User.get(id=1),
                           filename="Test_%d" % i,
                           task_type=0) for i in range(30))).execute()

    AffiliationRecord.insert_many((dict(is_active=False,
                                        task=Task.get(id=1),
                                        put_code=90,
                                        external_id="Test_%d" % i,
                                        status="Test_%d" % i,
                                        first_name="Test_%d" % i,
                                        last_name="Test_%d" % i,
                                        email="Test_%d" % i,
                                        orcid="123112311231%d" % i,
                                        organisation="Test_%d" % i,
                                        affiliation_type="Test_%d" % i,
                                        role="Test_%d" % i,
                                        department="Test_%d" % i,
                                        city="Test_%d" % i,
                                        state="Test_%d" % i,
                                        country="Test_%d" % i,
                                        disambiguated_id="Test_%d" % i,
                                        disambiguation_source="Test_%d" % i)
                                   for i in range(10))).execute()

    PropertyRecord.insert_many((dict(type="URL",
                                     is_active=False,
                                     task=Task.get(id=1),
                                     put_code=90,
                                     status="Test_%d" % i,
                                     first_name="Test_%d" % i,
                                     last_name="Test_%d" % i,
                                     email="Test_%d" % i,
                                     orcid="123112311231%d" % i,
                                     name="Test_%d" % i,
                                     value="Test_%d" % i,
                                     visibility="Test_%d" % i,
                                     display_index=i)
                                for i in range(10))).execute()

    PropertyRecord.insert_many((dict(type="NAME",
                                     is_active=False,
                                     task=Task.get(id=1),
                                     put_code=90,
                                     status="Test_%d" % i,
                                     first_name="Test_%d" % i,
                                     last_name="Test_%d" % i,
                                     email="Test_%d" % i,
                                     orcid="123112311231%d" % i,
                                     value="Test_%d" % i,
                                     visibility="Test_%d" % i,
                                     display_index=i)
                                for i in range(10))).execute()

    PropertyRecord.insert_many((dict(type="KEYWORD",
                                     is_active=False,
                                     task=Task.get(id=1),
                                     put_code=90,
                                     status="Test_%d" % i,
                                     first_name="Test_%d" % i,
                                     last_name="Test_%d" % i,
                                     email="Test_%d" % i,
                                     orcid="123112311231%d" % i,
                                     value="Test_%d" % i,
                                     visibility="Test_%d" % i,
                                     display_index=i)
                                for i in range(10))).execute()

    FundingRecord.insert_many(
        (dict(task=Task.get(id=1),
              title="Test_%d" % i,
              translated_title="Test_%d" % i,
              translated_title_language_code="Test_%d" % i,
              type="Test_%d" % i,
              organization_defined_type="Test_%d" % i,
              short_description="Test_%d" % i,
              amount="Test_%d" % i,
              currency="Test_%d" % i,
              org_name="Test_%d" % i,
              city="Test_%d" % i,
              region="Test_%d" % i,
              country="Test_%d" % i,
              disambiguated_id="Test_%d" % i,
              disambiguation_source="Test_%d" % i,
              is_active=False,
              status="Test_%d" % i) for i in range(10))).execute()

    record = FundingRecord.get()
    FundingContributor.insert_many((dict(record=record,
                                         orcid="123112311231%d" % i,
                                         name="Test_%d" % i,
                                         role="Test_%d" % i)
                                    for i in range(10))).execute()

    FundingInvitee.insert_many((dict(record=record,
                                     orcid="123112311231%d" % i,
                                     first_name="Test_%d" % i,
                                     last_name="Test_%d" % i,
                                     put_code=i,
                                     status="Test_%d" % i,
                                     identifier="%d" % i,
                                     visibility="Test_%d" % i,
                                     email="Test_%d" % i)
                                for i in range(10))).execute()

    ExternalId.insert_many((dict(record=record,
                                 type="Test_%d" % i,
                                 value="Test_%d" % i,
                                 url="Test_%d" % i,
                                 relationship="Test_%d" % i)
                            for i in range(10))).execute()

    task = Task.get()
    PeerReviewRecord.insert_many(
        (dict(task=task,
              review_group_id="issn:1212_%d" % i,
              reviewer_role="reviewer_%d" % i,
              review_url="xyz_%d" % i,
              review_type="REVIEW_%d" % i,
              subject_external_id_type="doi_%d" % i,
              subject_external_id_value="1212_%d" % i,
              subject_external_id_url="url/SELF_%d" % i,
              subject_external_id_relationship="SELF_%d" % i,
              subject_container_name="Journal title_%d" % i,
              subject_type="JOURNAL_ARTICLE_%d" % i,
              subject_name_title="name_%d" % i,
              subject_name_subtitle="subtitle_%d" % i,
              subject_name_translated_title_lang_code="en",
              subject_name_translated_title="sdsd_%d" % i,
              subject_url="url_%d" % i,
              convening_org_name="THE ORGANISATION_%d" % i,
              convening_org_city="auckland_%d" % i,
              convening_org_region="auckland_%d" % i,
              convening_org_country="nz_%d" % i,
              convening_org_disambiguated_identifier="123_%d" % i,
              convening_org_disambiguation_source="1212_%d" % i,
              is_active=False) for i in range(10))).execute()

    record = PeerReviewRecord.get()
    PeerReviewExternalId.insert_many((dict(record=record,
                                           type="Test1_%d" % i,
                                           value="Test1_%d" % i,
                                           url="Test1_%d" % i,
                                           relationship="Test1_%d" % i)
                                      for i in range(10))).execute()

    PeerReviewInvitee.insert_many((dict(record=record,
                                        orcid="1231123112311%d" % i,
                                        first_name="Test1_%d" % i,
                                        last_name="Test1_%d" % i,
                                        put_code=i,
                                        status="Test1_%d" % i,
                                        identifier="1%d" % i,
                                        visibility="PUBLIC",
                                        email="Test1_%d" % i)
                                   for i in range(10))).execute()

    WorkRecord.insert_many((dict(task=task,
                                 title="Test_%d" % i,
                                 subtitle="Test_%d" % i,
                                 translated_title="Test_%d" % i,
                                 translated_title_language_code="Test_%d" % i,
                                 journal_title="Test_%d" % i,
                                 short_description="Test_%d" % i,
                                 citation_type="Test_%d" % i,
                                 citation_value="Test_%d" % i,
                                 type="Test_%d" % i,
                                 url="Test_%d" % i,
                                 language_code="Test_%d" % i,
                                 country="Test_%d" % i,
                                 is_active=False,
                                 status="Test_%d" % i)
                            for i in range(10))).execute()

    record = WorkRecord.get()
    WorkContributor.insert_many((dict(record=record,
                                      orcid="123112311231%d" % i,
                                      name="Test_%d" % i,
                                      contributor_sequence="%d" % i,
                                      role="Test_%d" % i)
                                 for i in range(10))).execute()

    WorkExternalId.insert_many((dict(record=record,
                                     type="Test_%d" % i,
                                     value="Test_%d" % i,
                                     url="Test_%d" % i,
                                     relationship="Test_%d" % i)
                                for i in range(10))).execute()

    WorkInvitee.insert_many((dict(record=record,
                                  orcid="123112311231%d" % i,
                                  first_name="Test_%d" % i,
                                  last_name="Test_%d" % i,
                                  put_code=i,
                                  status="Test_%d" % i,
                                  identifier="%d" % i,
                                  visibility="Test_%d" % i,
                                  email="Test_%d" % i)
                             for i in range(10))).execute()

    yield testdb
Пример #3
0
def test_affiliation_api(client, mocker):
    """Test affiliation API in various formats."""
    exception = mocker.patch.object(client.application.logger, "exception")
    capture_event = mocker.patch(
        "sentry_sdk.transport.HttpTransport.capture_event")
    resp = client.post(
        "/oauth/token",
        content_type="application/x-www-form-urlencoded",
        data=
        b"grant_type=client_credentials&client_id=TEST0-ID&client_secret=TEST0-SECRET"
    )
    data = json.loads(resp.data)
    access_token = data["access_token"]
    resp = client.post(
        "/api/v1.0/affiliations/?filename=TEST42.csv",
        headers=dict(authorization=f"Bearer {access_token}"),
        content_type="text/csv",
        data=
        b"First Name,Last Name,email,Organisation,Affiliation Type,Role,Department,Start Date,"
        b"End Date,City,State,Country,Disambiguated Id,Disambiguated Source\n"
        b"Researcher,Par,[email protected],Royal Org1,Staff,Programme Guide - "
        b"ORCID,Research Funding,2016-09,,Wellington,SATE,NZ,,\n"
        b"Roshan,Pawar,[email protected],Royal Org1,Staff,AAA,Research "
        b"Funding,2016-09,,Wellington,SATE,NZ,,\n"
        b"Roshan,Pawar,[email protected],Royal Org1,Student,BBB,Research "
        b"Funding,2016-09,,Wellington,SATE,New Zealand,,")
    data = json.loads(resp.data)
    assert data["filename"] == "TEST42.csv"
    assert data["task-type"] == "AFFILIATION"
    assert len(data["records"]) == 3
    task_id = data["id"]

    resp = client.get("/api/v1.0/tasks",
                      headers=dict(authorization=f"Bearer {access_token}"))
    tasks = json.loads(resp.data)
    assert tasks[0]["id"] == task_id

    resp = client.get("/api/v1.0/tasks?type=AFFILIATION",
                      headers=dict(authorization=f"Bearer {access_token}"))
    tasks = json.loads(resp.data)
    assert tasks[0]["id"] == task_id

    resp = client.get("/api/v1.0/tasks?type=AFFILIATION&page=1&page_size=20",
                      headers=dict(authorization=f"Bearer {access_token}"))
    tasks = json.loads(resp.data)
    assert tasks[0]["id"] == task_id

    task_copy = copy.deepcopy(data)
    del (task_copy["id"])
    task_copy["filename"] = "TASK-COPY.csv"
    resp = client.post("/api/v1.0/affiliations/",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(task_copy))
    assert Task.select().count() == 2

    for r in data["records"]:
        del (r["id"])
        r["city"] = "TEST000"
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(data))
    data = json.loads(resp.data)
    assert len(resp.json["records"]) == 3
    # should get a new set of records

    del (data["records"][2])
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(data))
    assert len(resp.json["records"]) == 2

    incorrect_data = copy.deepcopy(data)
    incorrect_data["records"].insert(0, {
        "first-name": "TEST000 FN",
        "last-name": "TEST000 LN",
    })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(incorrect_data))
    assert resp.status_code == 422
    assert resp.json["error"] == "Validation error."

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    incorrect_data = copy.deepcopy(resp.json)
    incorrect_data["records"].insert(
        0, {
            "email": "*****@*****.**",
            "first-name": "TEST000 FN",
            "last-name": "TEST000 LN",
        })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(incorrect_data))
    assert resp.status_code == 422
    assert resp.json["error"] == "Validation error."

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    new_data = copy.deepcopy(resp.json)
    new_data["records"].insert(
        0, {
            "email": "*****@*****.**",
            "first-name": "TEST000 FN",
            "last-name": "TEST000 LN",
            "affiliation-type": "staff",
            "city": "TEST000"
        })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(new_data))
    data = json.loads(resp.data)
    assert resp.status_code == 200
    assert len(data["records"]) == 3

    resp = client.put(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"),
                      content_type="application/json",
                      data=json.dumps(data))
    data = json.loads(resp.data)
    assert resp.status_code == 200
    assert len(resp.json["records"]) == 3

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    new_data = copy.deepcopy(resp.json)
    for i, r in enumerate(new_data["records"]):
        new_data["records"][i] = {"id": r["id"], "is-active": True}
    resp = client.patch(f"/api/v1.0/affiliations/{task_id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    assert resp.status_code == 200
    assert len(resp.json["records"]) == 3
    assert all(r["is-active"] for r in resp.json["records"])
    assert all(r["city"] == "TEST000" for r in resp.json["records"])

    resp = client.head(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert "Last-Modified" in resp.headers

    resp = client.head("/api/v1.0/affiliations/999999999",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    resp = client.get("/api/v1.0/affiliations/999999999",
                      headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    resp = client.patch("/api/v1.0/affiliations/999999999",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    assert resp.status_code == 404

    with patch.object(Task, "get", side_effect=Exception("ERROR")):
        resp = client.delete(
            f"/api/v1.0/affiliations/{task_id}",
            headers=dict(authorization=f"Bearer {access_token}"))
        assert resp.status_code == 400
        assert resp.json == {
            "error": "Unhandled exception occurred.",
            "exception": "ERROR"
        }

    resp = client.delete(f"/api/v1.0/affiliations/{task_id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert Task.select().count() == 1

    resp = client.delete(f"/api/v1.0/affiliations/{task_id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    other_user = User.get(email="*****@*****.**")
    other_task = Task.create(created_by=other_user,
                             org=other_user.organisation,
                             filename="OTHER.csv",
                             task_type=TaskType.AFFILIATION)

    resp = client.head(f"/api/v1.0/affiliations/{other_task.id}",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.get(f"/api/v1.0/affiliations/{other_task.id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.patch(f"/api/v1.0/affiliations/{other_task.id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    assert resp.status_code == 403

    resp = client.delete(f"/api/v1.0/affiliations/{other_task.id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.patch(f"/api/v1.0/affiliations/{task_id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=b'')
    assert resp.status_code == 400

    resp = client.post("/api/v1.0/affiliations/?filename=TEST42.csv",
                       headers=dict(authorization=f"Bearer {access_token}",
                                    accept="text/yaml"),
                       content_type="text/yaml",
                       data="""task-type: AFFILIATION
filename: TEST42.yml
records:
- affiliation-type: student
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: BBB
  start-date: 2016-09
- affiliation-type: staff
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: AAA
  start-date: 2016-09
- affiliation-type: staff
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Researcher
  is-active: false
  last-name: Par
  organisation: Royal Org1
  role: Programme Guide - ORCID
  start-date: 2016-09
""")
    assert resp.json["filename"] == "TEST42.yml"
    assert resp.json["task-type"] == "AFFILIATION"
    assert len(resp.json["records"]) == 3
    task_id = resp.json["id"]
    task = Task.get(id=task_id)
    assert task.affiliation_records.count() == 3

    resp = client.put(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}",
                                   accept="text/yaml"),
                      content_type="text/yaml",
                      data="""task-type: AFFILIATION
filename: TEST42.yml
records:
- affiliation-type: student
  id: 9999999999
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: BBB
  start-date: 2016-09
""")
    assert resp.status_code == 400
    assert resp.json["error"] == "Unhandled exception occurred."
    assert "Instance matching query does not exist" in resp.json["exception"]

    with patch.object(AffiliationRecord, "get",
                      side_effect=Exception("ERROR")):
        resp = client.put(f"/api/v1.0/affiliations/{task_id}",
                          headers=dict(authorization=f"Bearer {access_token}",
                                       accept="text/yaml"),
                          content_type="text/yaml",
                          data="""task-type: AFFILIATION
filename: TEST42.yml
records:
- affiliation-type: student
  id: 9999999999
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: BBB
  start-date: 2016-09
""")
        assert resp.status_code == 400
        assert resp.json == {
            "error": "Unhandled exception occurred.",
            "exception": "ERROR"
        }

    resp = client.post(f"/api/v1.0/affiliations/?filename=TEST42.csv",
                       headers=dict(authorization=f"Bearer {access_token}",
                                    accept="text/yaml"),
                       content_type="text/yaml",
                       data="""task-type: INCORRECT
filename: TEST42.yml
records:
- affiliation-type: student
  id: 9999999999
""")
    assert resp.status_code == 422
    assert resp.json["error"] == "Validation error."
    assert "INCORRECT" in resp.json["message"]

    resp = client.post("/api/v1.0/affiliations/?filename=TEST_ERROR.csv",
                       headers=dict(authorization=f"Bearer {access_token}",
                                    accept="text/yaml"),
                       content_type="text/yaml",
                       data="""task-type: AFFILIATION
filename: TEST_ERROR.yml
records:
- affiliation-type: student
something fishy is going here...
""")
    assert resp.status_code == 415
    assert resp.json[
        "error"] == "Invalid request format. Only JSON, CSV, or TSV are acceptable."
    assert "something fishy is going here..." in resp.json["message"]
    exception.assert_called()
    capture_event.assert_called()
Пример #4
0
def test_affiliation_api(client):
    """Test affiliation API in various formats."""
    resp = client.post(
        "/oauth/token",
        content_type="application/x-www-form-urlencoded",
        data=
        b"grant_type=client_credentials&client_id=TEST0-ID&client_secret=TEST0-SECRET"
    )
    data = json.loads(resp.data)
    access_token = data["access_token"]
    resp = client.post(
        "/api/v1.0/affiliations/?filename=TEST42.csv",
        headers=dict(authorization=f"Bearer {access_token}"),
        content_type="text/csv",
        data=
        b"First Name,Last Name,email,Organisation,Affiliation Type,Role,Department,Start Date,"
        b"End Date,City,State,Country,Disambiguated Id,Disambiguated Source\n"
        b"Researcher,Par,[email protected],Royal Org1,Staff,Programme Guide - "
        b"ORCID,Research Funding,2016-09,,Wellington,SATE,NZ,,\n"
        b"Roshan,Pawar,[email protected],Royal Org1,Staff,AAA,Research "
        b"Funding,2016-09,,Wellington,SATE,NZ,,\n"
        b"Roshan,Pawar,[email protected],Royal Org1,Student,BBB,Research "
        b"Funding,2016-09,,Wellington,SATE,New Zealand,,")
    data = json.loads(resp.data)
    assert data["filename"] == "TEST42.csv"
    assert data["task-type"] == "AFFILIATION"
    assert len(data["records"]) == 3
    task_id = data["id"]

    resp = client.get("/api/v1.0/tasks",
                      headers=dict(authorization=f"Bearer {access_token}"))
    tasks = json.loads(resp.data)
    assert tasks[0]["id"] == task_id

    task_copy = copy.deepcopy(data)
    del (task_copy["id"])
    task_copy["filename"] = "TASK-COPY.csv"
    resp = client.post("/api/v1.0/affiliations/",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(task_copy))
    assert Task.select().count() == 2

    for r in data["records"]:
        del (r["id"])
        r["city"] = "TEST000"
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(data))
    data = json.loads(resp.data)
    assert len(data["records"]) == 3
    # should get a new set of records

    del (data["records"][2])
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(data))
    new_data = json.loads(resp.data)
    assert len(new_data["records"]) == 2

    incorrect_data = copy.deepcopy(data)
    incorrect_data["records"].insert(0, {
        "first-name": "TEST000 FN",
        "last-name": "TEST000 LN",
    })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(incorrect_data))
    data = json.loads(resp.data)
    assert resp.status_code == 422
    assert data["error"] == "Validation error."

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    data = json.loads(resp.data)
    incorrect_data = copy.deepcopy(data)
    incorrect_data["records"].insert(
        0, {
            "email": "*****@*****.**",
            "first-name": "TEST000 FN",
            "last-name": "TEST000 LN",
        })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(incorrect_data))
    data = json.loads(resp.data)
    assert resp.status_code == 422
    assert data["error"] == "Validation error."

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    data = json.loads(resp.data)
    new_data = copy.deepcopy(data)
    new_data["records"].insert(
        0, {
            "email": "*****@*****.**",
            "first-name": "TEST000 FN",
            "last-name": "TEST000 LN",
            "affiliation-type": "staff",
            "city": "TEST000"
        })
    resp = client.post(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"),
                       content_type="application/json",
                       data=json.dumps(new_data))
    data = json.loads(resp.data)
    assert resp.status_code == 200
    assert len(data["records"]) == 3

    resp = client.put(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"),
                      content_type="application/json",
                      data=json.dumps(data))
    data = json.loads(resp.data)
    assert resp.status_code == 200
    assert len(data["records"]) == 3

    resp = client.get(f"/api/v1.0/affiliations/{task_id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    data = json.loads(resp.data)
    new_data = copy.deepcopy(data)
    for i, r in enumerate(new_data["records"]):
        new_data["records"][i] = {"id": r["id"], "is-active": True}
    resp = client.patch(f"/api/v1.0/affiliations/{task_id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    data = json.loads(resp.data)
    assert resp.status_code == 200
    assert len(data["records"]) == 3
    assert all(r["is-active"] for r in data["records"])
    assert all(r["city"] == "TEST000" for r in data["records"])

    resp = client.head(f"/api/v1.0/affiliations/{task_id}",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert "Last-Modified" in resp.headers

    resp = client.head("/api/v1.0/affiliations/999999999",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    resp = client.get("/api/v1.0/affiliations/999999999",
                      headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    resp = client.patch("/api/v1.0/affiliations/999999999",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    assert resp.status_code == 404

    resp = client.delete(f"/api/v1.0/affiliations/{task_id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert Task.select().count() == 1

    resp = client.delete(f"/api/v1.0/affiliations/{task_id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 404

    other_user = User.get(email="*****@*****.**")
    other_task = Task.create(created_by=other_user,
                             org=other_user.organisation,
                             filename="OTHER.csv",
                             task_type=TaskType.AFFILIATION)

    resp = client.head(f"/api/v1.0/affiliations/{other_task.id}",
                       headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.get(f"/api/v1.0/affiliations/{other_task.id}",
                      headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.patch(f"/api/v1.0/affiliations/{other_task.id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=json.dumps(new_data))
    assert resp.status_code == 403

    resp = client.delete(f"/api/v1.0/affiliations/{other_task.id}",
                         headers=dict(authorization=f"Bearer {access_token}"))
    assert resp.status_code == 403

    resp = client.patch(f"/api/v1.0/affiliations/{task_id}",
                        headers=dict(authorization=f"Bearer {access_token}"),
                        content_type="application/json",
                        data=b'')
    assert resp.status_code == 400

    resp = client.post("/api/v1.0/affiliations/?filename=TEST42.csv",
                       headers=dict(authorization=f"Bearer {access_token}",
                                    accept="text/yaml"),
                       content_type="text/yaml",
                       data="""task-type: AFFILIATION
filename: TEST42.yml
records:
- affiliation-type: student
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: BBB
  start-date: 2016-09
- affiliation-type: staff
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Roshan
  last-name: Pawar
  organisation: Royal Org1
  role: AAA
  start-date: 2016-09
- affiliation-type: staff
  city: Wellington
  country: NZ
  department: Research Funding
  email: [email protected]
  first-name: Researcher
  is-active: false
  last-name: Par
  organisation: Royal Org1
  role: Programme Guide - ORCID
  start-date: 2016-09
""")
    data = json.loads(resp.data)
    assert data["filename"] == "TEST42.yml"
    assert data["task-type"] == "AFFILIATION"
    assert len(data["records"]) == 3
    task_id = data["id"]
    task = Task.get(id=task_id)
    assert task.affiliation_records.count() == 3