Example #1
0
def test_send_with_event(patch_smtp, api_client, example_draft, event):
    # Create a draft
    r = api_client.post_data('/drafts', example_draft)
    msgs = patch_smtp
    assert r.status_code == 200
    draft_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    # Send the draft along with an event ID to use for invites
    r = api_client.post_data('/send',
                             {'draft_id': draft_public_id,
                              'version': version,
                              'event_id': event.public_id})
    assert r.status_code == 200

    # Make sure one message was sent
    assert len(msgs) == 1
    recipients, raw_msg = msgs[0]
    msg = mime.from_string(raw_msg)

    # Check the MIME body of the message to make sure the event is there
    parts = []
    for mimepart in msg.walk(with_self=msg.content_type.is_singlepart()):
        format_type = mimepart.content_type.format_type
        subtype = mimepart.content_type.subtype
        parts.append((format_type, subtype))
    assert ('text', 'plain') in parts
    assert ('text', 'html') in parts
    assert ('text', 'calendar') in parts
Example #2
0
def test_contacts_updated(api_client):
    """Tests that draft-contact associations are properly created and
    updated."""
    draft = {"to": [{"email": "*****@*****.**"}, {"email": "*****@*****.**"}]}

    r = api_client.post_data("/drafts", draft)
    assert r.status_code == 200
    draft_id = json.loads(r.data)["id"]
    draft_version = json.loads(r.data)["version"]

    r = api_client.get_data("/[email protected]")
    assert len(r) == 1

    updated_draft = {"to": [{"email": "*****@*****.**"}, {"email": "*****@*****.**"}], "version": draft_version}

    r = api_client.put_data("/drafts/{}".format(draft_id), updated_draft)
    assert r.status_code == 200

    r = api_client.get_data("/[email protected]")
    assert len(r) == 1

    r = api_client.get_data("/[email protected]")
    assert len(r) == 0

    r = api_client.get_data("/[email protected]")
    assert len(r) == 1

    # Check that contacts aren't created for garbage recipients.
    r = api_client.post_data("/drafts", {"to": [{"name": "who", "email": "nope"}]})
    assert r.status_code == 200
    r = api_client.get_data("/threads?to=nope")
    assert len(r) == 0
    r = api_client.get_data("/contacts?filter=nope")
    assert len(r) == 0
def test_write_endpoints(db, setup_account, api_client, default_account):
    # Write operations (create, update, delete) succeed.
    r = api_client.post_data(
        '/drafts',
        data={
            'body': '<html><body><h2>Sea, birds and sand.</h2></body></html>'
        })
    assert r.status_code == 200
    draft_id = json.loads(r.data)['id']

    endpoint = '/messages/{}'.format(setup_account['message'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 200

    endpoint = '/events/{}'.format(setup_account['event'])
    r = api_client.delete(endpoint)
    assert r.status_code == 200

    default_account.sync_state = 'invalid'
    db.session.commit()

    # Write operations fail with an HTTP 403.
    r = api_client.post_data('/labels', data={"display_name": "Neu!"})
    assert r.status_code == 403

    endpoint = '/threads/{}'.format(setup_account['thread'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 403

    endpoint = '/drafts/{}'.format(draft_id)
    r = api_client.delete(endpoint)
    assert r.status_code == 403
Example #4
0
def test_send_draft(db, api_client, example_draft, default_account):

    r = api_client.post_data('/drafts', example_draft)
    assert r.status_code == 200
    public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    r = api_client.post_data('/send', {'draft_id': public_id,
                                       'version': version})
    assert r.status_code == 200

    draft = api_client.get_data('/drafts/{}'.format(public_id))
    assert draft is not None

    assert draft['object'] != 'draft'

    with crispin_client(default_account.id, default_account.provider) as c:
        criteria = ['NOT DELETED', 'SUBJECT "{0}"'.format(
            example_draft['subject'])]

        c.conn.select_folder(default_account.drafts_folder.name,
                             readonly=False)

        draft_uids = c.conn.search(criteria)
        assert not draft_uids, 'Message still in Drafts folder'

        c.conn.select_folder(default_account.sent_folder.name, readonly=False)

        sent_uids = c.conn.search(criteria)
        assert sent_uids, 'Message missing from Sent folder'

        c.conn.delete_messages(sent_uids)
        c.conn.expunge()
Example #5
0
def test_quoted_printable_encoding_avoided_for_compatibility(
        patch_smtp, api_client):
    # Test that messages with long lines don't get quoted-printable encoded,
    # for maximum server compatibility.
    api_client.post_data(
        '/send',
        {'to': [{'email': '*****@*****.**'}],
         'subject': 'In Catilinam',
         'body': 'Etenim quid est, Catilina, quod iam amplius exspectes, si '
         'neque nox tenebris obscurare coeptus nefarios neque privata domus '
         'parietibus continere voces conjurationis tuae potest? Si '
         'illustrantur, si erumpunt omnia? Muta iam istam mentem, mihi crede! '
         'obliviscere caedis atque incendiorum. Teneris undique: luce sunt '
         'clariora nobis tua consilia omnia; quae iam mecum licet recognoscas.'
         ' Meministine me ante diem duodecimum Kalendas Novembres dicere in '
         'senatu, fore in armis certo die, qui dies futurus esset ante diem '
         'sextum Kalendas Novembres, C. Manlium, audaciae satellitem atque '
         'administrum tuae? Num me fefellit, Catilina, non modo res tanta, tam'
         ' atrox, tamque incredibilis, verum id quod multo magis admirandum, '
         'dies? '})
    _, msg = patch_smtp[-1]
    parsed = mime.from_string(msg)
    assert len(parsed.parts) == 2
    for part in parsed.parts:
        if part.content_type.value == 'text/html':
            assert part.content_encoding[0] == 'base64'
        elif part.content_type.value == 'text/plain':
            assert part.content_encoding[0] in ('7bit', 'base64')
Example #6
0
def test_api_get(db, api_client, calendar):
    e_data = {'title': 'subj', 'when': {'time': 1},
              'calendar_id': calendar.public_id, 'location': 'InboxHQ'}
    e_data2 = {'title': 'subj2', 'when': {'time': 1},
               'calendar_id': calendar.public_id, 'location': 'InboxHQ'}
    api_client.post_data('/events', e_data)
    api_client.post_data('/events', e_data2)

    event_list = api_client.get_data('/events')

    event_ids = [event['id'] for event in event_list]

    c1found = False
    c2found = False
    for c_id in event_ids:
        event = api_client.get_data('/events/' + c_id)

        if event['title'] == 'subj':
            c1found = True

        if event['title'] == 'subj2':
            c2found = True

    assert c1found
    assert c2found
Example #7
0
def test_api_list(db, api_client, calendar):
    e_data = {'title': 'subj', 'description': 'body1',
              'calendar_id': calendar.public_id,
              'when': {'time': 1}, 'location': 'InboxHQ'}
    e_data2 = {'title': 'subj2', 'description': 'body2',
               'calendar_id': calendar.public_id,
               'when': {'time': 1}, 'location': 'InboxHQ'}
    api_client.post_data('/events', e_data)
    api_client.post_data('/events', e_data2)

    event_list = api_client.get_data('/events')
    event_titles = [event['title'] for event in event_list]
    assert 'subj' in event_titles
    assert 'subj2' in event_titles

    event_descriptions = [event['description'] for event in event_list]
    assert 'body1' in event_descriptions
    assert 'body2' in event_descriptions

    event_ids = [event['id'] for event in event_list]

    for e_id in event_ids:
        ev = db.session.query(Event).filter_by(public_id=e_id).one()
        db.session.delete(ev)
    db.session.commit()
Example #8
0
def test_send_rejected_without_recipients(api_client):
    r = api_client.post_data('/drafts', {'subject': 'Hello there'})
    draft_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    r = api_client.post_data('/send',
                             {'draft_id': draft_public_id,
                              'version': version})
    assert r.status_code == 400
Example #9
0
def test_multisend_init_rejected_with_existing_draft(api_client,
                                                     example_draft):
    r = api_client.post_data('/drafts', example_draft)
    draft_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    r = api_client.post_data('/send-multiple',
                             {'draft_id': draft_public_id,
                              'version': version})
    assert r.status_code == 400
Example #10
0
def test_invalid_timestamp(api_client, default_namespace):
    # Valid UNIX timestamp
    response = api_client.post_data(
        '/delta/generate_cursor', data={'start': int(time.time())})
    assert response.status_code == 200

    # Invalid timestamp
    response = api_client.post_data(
        '/delta/generate_cursor', data={'start': 1434591487647})
    assert response.status_code == 400
Example #11
0
def test_create_event(db, api_client, calendar):
    e_data = {'title': 'subj', 'description': 'body1',
              'calendar_id': calendar.public_id,
              'when': {'time': 1}, 'location': 'InboxHQ'}
    e_data2 = {'title': 'subj2', 'description': 'body2',
               'calendar_id': calendar.public_id,
               'when': {'time': 1}, 'location': 'InboxHQ'}
    api_client.post_data('/events', e_data)
    api_client.post_data('/events', e_data2)
    db.session.commit()
Example #12
0
def test_sent_messages_shown_in_delta(patch_smtp, api_client, example_draft):
    ts = int(time.time())
    r = api_client.post_data('/delta/generate_cursor', {'start': ts})
    cursor = json.loads(r.data)['cursor']
    r = api_client.post_data('/send', example_draft)
    message_id = json.loads(r.data)['id']
    deltas = api_client.get_data('/delta?cursor={}'.format(cursor))['deltas']
    message_delta = next((d for d in deltas if d['id'] == message_id), None)
    assert message_delta is not None
    assert message_delta['object'] == 'message'
    assert message_delta['event'] == 'create'
Example #13
0
def test_sending_from_email_alias(patch_smtp, api_client):
    api_client.post_data('/send',
                         {'to': [{'email': '*****@*****.**'}],
                          'from': [{'name': 'admin',
                                    'email': '*****@*****.**'}],
                          'subject': 'Banalities',
                          'body': '<html>Hello there</html>'})
    _, msg = patch_smtp[-1]
    parsed = mime.from_string(msg)
    assert 'From' in parsed.headers
    assert parsed.headers['From'] == 'admin <*****@*****.**>'
Example #14
0
def test_get_all_drafts(api_client, example_draft):
    r = api_client.post_data("/drafts", example_draft)
    first_public_id = json.loads(r.data)["id"]

    r = api_client.post_data("/drafts", example_draft)
    second_public_id = json.loads(r.data)["id"]

    drafts = api_client.get_data("/drafts")
    assert len(drafts) == 2
    assert first_public_id != second_public_id
    assert {first_public_id, second_public_id} == {draft["id"] for draft in drafts}
    assert all(item["object"] == "draft" for item in drafts)
Example #15
0
def test_reply_headers_set(db, patch_smtp, api_client, example_draft, thread,
                           message):
    message.message_id_header = '<*****@*****.**>'
    db.session.commit()
    thread_id = api_client.get_data('/threads')[0]['id']

    api_client.post_data('/send', {'to': [{'email': '*****@*****.**'}],
                                   'thread_id': thread_id})
    _, msg = patch_smtp[-1]
    parsed = mime.from_string(msg)
    assert 'In-Reply-To' in parsed.headers
    assert 'References' in parsed.headers
Example #16
0
def test_get_all_drafts(api_client, example_draft):
    r = api_client.post_data('/drafts', example_draft)
    first_public_id = json.loads(r.data)['id']

    r = api_client.post_data('/drafts', example_draft)
    second_public_id = json.loads(r.data)['id']

    drafts = api_client.get_data('/drafts')
    assert len(drafts) == 2
    assert first_public_id != second_public_id
    assert {first_public_id, second_public_id} == {draft['id'] for draft in
                                                   drafts}
    assert all(item['object'] == 'draft' for item in drafts)
Example #17
0
def test_delete_draft(api_client, thread, message):
    original_draft = {
        'subject': 'parent draft',
        'body': 'parent draft'
    }
    r = api_client.post_data('/drafts', original_draft)
    draft_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    updated_draft = {
        'subject': 'updated draft',
        'body': 'updated draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                            updated_draft)
    updated_public_id = json.loads(r.data)['id']
    updated_version = json.loads(r.data)['version']

    r = api_client.delete('/drafts/{}'.format(updated_public_id),
                          {'version': updated_version})

    # Check that drafts were deleted
    drafts = api_client.get_data('/drafts')
    assert not drafts

    # Check that no orphaned threads are around
    threads = api_client.get_data('/threads?subject=parent%20draft')
    assert not threads
    threads = api_client.get_data('/threads?subject=updated%20draft')
    assert not threads

    # And check that threads aren't deleted if they still have messages.
    thread_public_id = api_client.get_data('/threads')[0]['id']

    reply_draft = {
        'subject': 'test reply',
        'body': 'test reply',
        'thread_id': thread_public_id
    }
    r = api_client.post_data('/drafts', reply_draft)
    public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']
    thread = api_client.get_data('/threads/{}'.format(thread_public_id))
    assert len(thread['draft_ids']) > 0
    api_client.delete('/drafts/{}'.format(public_id),
                      {'version': version})
    thread = api_client.get_data('/threads/{}'.format(thread_public_id))
    assert thread
    assert len(thread['draft_ids']) == 0
def label_client(db, gmail_account):
    api_client = new_api_client(db, gmail_account.namespace)

    # Whereas calling generic_account always makes a new IMAP account,
    # calling gmail_account checks first to see if there's an existing
    # Gmail account and uses it if so. This can cause namespace
    # conflicts if a label is "created" more than once. Since
    # labels can't be deleted and then re-created, this fixture only
    # makes a new label if there are no existing labels.
    g_data = api_client.get_raw('/labels/')
    if not json.loads(g_data.data):
        api_client.post_data('/labels/',
                             {"display_name": "Test_Label"})
    return api_client
Example #19
0
def test_api_pessimistic_update(db, api_client, calendar, default_account):
    e_data = {
        'title': '',
        'calendar_id': calendar.public_id,
        'when': {'time': 1407542195},
    }

    e_resp = api_client.post_data('/events', e_data,
                                  headers={ "Api-Version": API_VERSIONS[1] })

    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data['object'] == 'event'
    assert e_resp_data['account_id'] == default_account.namespace.public_id
    assert e_resp_data['title'] == e_data['title']
    assert e_resp_data['when']['time'] == e_data['when']['time']
    assert 'id' in e_resp_data
    e_id = e_resp_data['id']

    e_update_data = {'title': 'new title'}
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data,
                                     headers={ "Api-Version": API_VERSIONS[1] })

    e_put_data = json.loads(e_put_resp.data)

    assert e_put_data['object'] == 'event'
    assert e_put_data['account_id'] == default_account.namespace.public_id
    assert e_put_data['id'] == e_id
    assert e_put_data['title'] == ''
    assert e_put_data['when']['object'] == 'time'
    assert e_put_data['when']['time'] == e_data['when']['time']
Example #20
0
def test_drafts_filter(api_client, example_draft):
    r = api_client.post_data("/drafts", example_draft)
    thread_id = json.loads(r.data)["thread_id"]

    reply_draft = {"subject": "test reply", "body": "test reply", "thread_id": thread_id}
    r = api_client.post_data("/drafts", reply_draft)

    _filter = "?thread_id=0000000000000000000000000"
    results = api_client.get_data("/drafts" + _filter)
    assert len(results) == 0

    results = api_client.get_data("/drafts?thread_id={}".format(thread_id))
    assert len(results) == 2

    results = api_client.get_data("/drafts?offset={}&thread_id={}".format(1, thread_id))
    assert len(results) == 1
Example #21
0
def test_api_create(db, api_client, calendar, default_account):
    e_data = {
        "title": "Friday Office Party",
        "calendar_id": calendar.public_id,
        "when": {
            "time": 1407542195
        },
        "location": "Nylas HQ",
    }

    e_resp = api_client.post_data("/events", e_data)
    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data["object"] == "event"
    assert e_resp_data["account_id"] == default_account.namespace.public_id
    assert e_resp_data["title"] == e_data["title"]
    assert e_resp_data["location"] == e_data["location"]
    assert e_resp_data["when"]["time"] == e_data["when"]["time"]
    assert "id" in e_resp_data
    e_id = e_resp_data["id"]
    e_get_resp = api_client.get_data("/events/" + e_id)

    assert e_get_resp["object"] == "event"
    assert e_get_resp["account_id"] == default_account.namespace.public_id
    assert e_get_resp["id"] == e_id
    assert e_get_resp["title"] == e_data["title"]
    assert e_get_resp["when"]["time"] == e_data["when"]["time"]
Example #22
0
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {"subject": "original draft", "body": "parent draft"}
        r = api_client.post_data("/drafts", original_draft)
        draft_public_id = json.loads(r.data)["id"]
        version = json.loads(r.data)["version"]
        assert version == 0

        freezer.tick()

        updated_draft = {"subject": "updated draft", "body": "updated draft", "version": version}

        r = api_client.put_data("/drafts/{}".format(draft_public_id), updated_draft)
        updated_public_id = json.loads(r.data)["id"]
        updated_version = json.loads(r.data)["version"]

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data("/drafts")
        assert len(drafts) == 1
        assert drafts[0]["id"] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data("/threads/{}".format(drafts[0]["thread_id"]))
        assert thread["subject"] == "updated draft"
        assert thread["first_message_timestamp"] == drafts[0]["date"]
        assert thread["last_message_timestamp"] == drafts[0]["date"]
def test_api_create_multiple(db, api_client, calendar):
    e_data = {
        'title': 'Friday Office Party',
        'when': {'time': 1407542195},
        'calendar_id': calendar.public_id,
        'participants': [{
            'email': '*****@*****.**',
        }, {
            'email': '*****@*****.**',
        }]
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)

    assert len(e_resp_data['participants']) == 2
    for participant in e_resp_data['participants']:
        res = [e for e in e_data['participants']
               if e['email'] == participant['email']]
        assert len(res) == 1

    participant0 = e_resp_data['participants'][0]
    participant1 = e_resp_data['participants'][1]
    assert participant0['name'] is None
    assert participant0['status'] == 'noreply'
    assert participant1['name'] is None
    assert participant1['status'] == 'noreply'
Example #24
0
def test_api_pessimistic_update(db, api_client, calendar, default_account):
    e_data = {
        "title": "",
        "calendar_id": calendar.public_id,
        "when": {
            "time": 1407542195
        },
    }

    e_resp = api_client.post_data("/events",
                                  e_data,
                                  headers={"Api-Version": API_VERSIONS[1]})

    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data["object"] == "event"
    assert e_resp_data["account_id"] == default_account.namespace.public_id
    assert e_resp_data["title"] == e_data["title"]
    assert e_resp_data["when"]["time"] == e_data["when"]["time"]
    assert "id" in e_resp_data
    e_id = e_resp_data["id"]

    e_update_data = {"title": "new title"}
    e_put_resp = api_client.put_data("/events/" + e_id,
                                     e_update_data,
                                     headers={"Api-Version": API_VERSIONS[1]})

    e_put_data = json.loads(e_put_resp.data)

    assert e_put_data["object"] == "event"
    assert e_put_data["account_id"] == default_account.namespace.public_id
    assert e_put_data["id"] == e_id
    assert e_put_data["title"] == ""
    assert e_put_data["when"]["object"] == "time"
    assert e_put_data["when"]["time"] == e_data["when"]["time"]
Example #25
0
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {"subject": "original draft", "body": "parent draft"}
        r = api_client.post_data("/drafts", original_draft)
        draft_public_id = json.loads(r.data)["id"]
        version = json.loads(r.data)["version"]
        assert version == 0

        freezer.tick()

        updated_draft = {
            "subject": "updated draft",
            "body": "updated draft",
            "version": version,
        }

        r = api_client.put_data("/drafts/{}".format(draft_public_id),
                                updated_draft)
        updated_public_id = json.loads(r.data)["id"]
        updated_version = json.loads(r.data)["version"]

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data("/drafts")
        assert len(drafts) == 1
        assert drafts[0]["id"] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data("/threads/{}".format(
            drafts[0]["thread_id"]))
        assert thread["subject"] == "updated draft"
        assert thread["first_message_timestamp"] == drafts[0]["date"]
        assert thread["last_message_timestamp"] == drafts[0]["date"]
Example #26
0
def test_malformed_subject_rejected(api_client, example_draft_bad_subject):
    r = api_client.post_data('/send', example_draft_bad_subject)
    assert r.status_code == 400

    decoded = json.loads(r.get_data())
    assert decoded['type'] == 'invalid_request_error'
    assert decoded['message'] == '"subject" should be a string'
Example #27
0
def test_multisend_handle_recipients_rejected(recipients_refused, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data('/send-multiple/' + multisend['id'],
                             multisend['send_req'])
    assert r.status_code == 402
    assert json.loads(r.data)['message'] == 'Sending to all recipients failed'
Example #28
0
def test_account_validation(api_client, db, default_namespace):

    draft = {'body': '<html><body><h2>Sea, birds and sand.</h2></body></html>'}

    r = api_client.post_data('/drafts', draft)
    assert r.status_code == 200

    namespace_id = json.loads(r.data)['account_id']
    account = db.session.query(Namespace).filter(
        Namespace.public_id == namespace_id).first().account

    account.sync_state = 'invalid'
    db.session.commit()

    r = api_client.post_data('/drafts', draft)
    assert r.status_code == 403
Example #29
0
def test_attachment_has_same_id(api_client, uploaded_file_ids, draft):
    attachment_id = uploaded_file_ids.pop()
    draft['file_ids'] = [attachment_id]
    r = api_client.post_data('/drafts', draft)
    assert r.status_code == 200
    draft_resp = json.loads(r.data)
    assert attachment_id in [x['id'] for x in draft_resp['files']]
Example #30
0
def test_conflicting_updates(api_client):
    original_draft = {'subject': 'parent draft', 'body': 'parent draft'}
    r = api_client.post_data('/drafts', original_draft)
    original_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    updated_draft = {
        'subject': 'updated draft',
        'body': 'updated draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(original_public_id),
                            updated_draft)
    assert r.status_code == 200
    updated_public_id = json.loads(r.data)['id']
    updated_version = json.loads(r.data)['version']
    assert updated_version != version

    conflicting_draft = {
        'subject': 'conflicting draft',
        'body': 'conflicting draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(original_public_id),
                            conflicting_draft)
    assert r.status_code == 409

    drafts = api_client.get_data('/drafts')
    assert len(drafts) == 1
    assert drafts[0]['id'] == updated_public_id
Example #31
0
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {'subject': 'original draft', 'body': 'parent draft'}
        r = api_client.post_data('/drafts', original_draft)
        draft_public_id = json.loads(r.data)['id']
        version = json.loads(r.data)['version']
        assert version == 0

        freezer.tick()

        updated_draft = {
            'subject': 'updated draft',
            'body': 'updated draft',
            'version': version
        }

        r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                                updated_draft)
        updated_public_id = json.loads(r.data)['id']
        updated_version = json.loads(r.data)['version']

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data('/drafts')
        assert len(drafts) == 1
        assert drafts[0]['id'] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data('/threads/{}'.format(
            drafts[0]['thread_id']))
        assert thread['subject'] == 'updated draft'
        assert thread['first_message_timestamp'] == drafts[0]['date']
        assert thread['last_message_timestamp'] == drafts[0]['date']
def test_api_create(db, api_client, calendar):
    e_data = {
        'title': 'Friday Office Party',
        'when': {'time': 1407542195},
        'calendar_id': calendar.public_id,
        'participants': [{
            'name': 'alyssa p. hacker',
            'email': '*****@*****.**'
        }]
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)

    assert len(e_resp_data['participants']) == 1
    participant = e_resp_data['participants'][0]
    assert participant['name'] == e_data['participants'][0]['name']
    assert participant['email'] == e_data['participants'][0]['email']
    assert participant['status'] == 'noreply'

    e_resp_data = api_client.get_data('/events/' + e_resp_data['id'])

    assert len(e_resp_data['participants']) == 1
    participant = e_resp_data['participants'][0]
    assert participant['name'] == e_data['participants'][0]['name']
    assert participant['email'] == e_data['participants'][0]['email']
    assert participant['status'] == 'noreply'
Example #33
0
def test_conflicting_updates(api_client):
    original_draft = {"subject": "parent draft", "body": "parent draft"}
    r = api_client.post_data("/drafts", original_draft)
    original_public_id = json.loads(r.data)["id"]
    version = json.loads(r.data)["version"]

    updated_draft = {
        "subject": "updated draft",
        "body": "updated draft",
        "version": version,
    }
    r = api_client.put_data("/drafts/{}".format(original_public_id),
                            updated_draft)
    assert r.status_code == 200
    updated_public_id = json.loads(r.data)["id"]
    updated_version = json.loads(r.data)["version"]
    assert updated_version != version

    conflicting_draft = {
        "subject": "conflicting draft",
        "body": "conflicting draft",
        "version": version,
    }
    r = api_client.put_data("/drafts/{}".format(original_public_id),
                            conflicting_draft)
    assert r.status_code == 409

    drafts = api_client.get_data("/drafts")
    assert len(drafts) == 1
    assert drafts[0]["id"] == updated_public_id
Example #34
0
def test_reply_headers_set(db, patch_smtp, api_client, example_draft, thread,
                           message):
    message.message_id_header = '<*****@*****.**>'
    db.session.commit()
    thread_id = api_client.get_data('/threads')[0]['id']

    api_client.post_data('/send', {
        'to': [{
            'email': '*****@*****.**'
        }],
        'thread_id': thread_id
    })
    _, msg = patch_smtp[-1]
    parsed = mime.from_string(msg)
    assert 'In-Reply-To' in parsed.headers
    assert 'References' in parsed.headers
Example #35
0
def test_contacts_updated(api_client):
    """Tests that draft-contact associations are properly created and
    updated."""
    draft = {
        'to': [{'email': '*****@*****.**'}, {'email': '*****@*****.**'}]
    }

    r = api_client.post_data('/drafts', draft)
    assert r.status_code == 200
    draft_id = json.loads(r.data)['id']
    draft_version = json.loads(r.data)['version']

    r = api_client.get_data('/[email protected]')
    assert len(r) == 1

    updated_draft = {
        'to': [{'email': '*****@*****.**'}, {'email': '*****@*****.**'}],
        'version': draft_version
    }

    r = api_client.put_data('/drafts/{}'.format(draft_id), updated_draft)
    assert r.status_code == 200

    r = api_client.get_data('/[email protected]')
    assert len(r) == 1

    r = api_client.get_data('/[email protected]')
    assert len(r) == 0

    r = api_client.get_data('/[email protected]')
    assert len(r) == 1
Example #36
0
def test_api_pessimistic_delete(db, api_client, calendar, default_account):
    e_data = {
        "title": "",
        "calendar_id": calendar.public_id,
        "when": {
            "time": 1407542195
        },
    }

    e_resp = api_client.post_data("/events",
                                  e_data,
                                  headers={"Api-Version": API_VERSIONS[1]})
    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data["object"] == "event"
    assert e_resp_data["title"] == e_data["title"]
    assert e_resp_data["when"]["time"] == e_data["when"]["time"]
    assert "id" in e_resp_data
    e_id = e_resp_data["id"]

    e_delete_resp = api_client.delete("/events/" + e_id,
                                      headers={"Api-Version": API_VERSIONS[1]})
    assert e_delete_resp.status_code == 200

    e_resp = api_client.get_data("/events/" + e_id)
    assert e_resp["status"] == "confirmed"
Example #37
0
def test_conflicting_updates(api_client):
    original_draft = {
        'subject': 'parent draft',
        'body': 'parent draft'
    }
    r = api_client.post_data('/drafts', original_draft)
    original_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    updated_draft = {
        'subject': 'updated draft',
        'body': 'updated draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(original_public_id),
                            updated_draft)
    assert r.status_code == 200
    updated_public_id = json.loads(r.data)['id']
    updated_version = json.loads(r.data)['version']
    assert updated_version != version

    conflicting_draft = {
        'subject': 'conflicting draft',
        'body': 'conflicting draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(original_public_id),
                            conflicting_draft)
    assert r.status_code == 409

    drafts = api_client.get_data('/drafts')
    assert len(drafts) == 1
    assert drafts[0]['id'] == updated_public_id
Example #38
0
def test_attachment_has_same_id(api_client, uploaded_file_ids, draft):
    attachment_id = uploaded_file_ids.pop()
    draft['file_ids'] = [attachment_id]
    r = api_client.post_data('/drafts', draft)
    assert r.status_code == 200
    draft_resp = json.loads(r.data)
    assert attachment_id in [x['id'] for x in draft_resp['files']]
def test_api_remove_participant(db, api_client, calendar):
    e_data = {
        'title': 'Friday Office Party',
        'when': {'time': 1407542195},
        'calendar_id': calendar.public_id,
        'participants': [{'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'}]
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)
    assert len(e_resp_data['participants']) == 5
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_resp_data['participants']
               if e['email'] == p['email']]
        assert len(res) == 1
        assert res[0]['name'] is None

    event_id = e_resp_data['id']
    e_data['participants'].pop()
    e_resp = api_client.put_data('/events/' + event_id, e_data)
    e_resp_data = json.loads(e_resp.data)
    assert len(e_resp_data['participants']) == 4
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_resp_data['participants']
               if e['email'] == p['email']]
        assert len(res) == 1
        assert p['name'] is None
Example #40
0
def test_attachment_has_same_id(api_client, uploaded_file_ids, draft):
    attachment_id = uploaded_file_ids.pop()
    draft["file_ids"] = [attachment_id]
    r = api_client.post_data("/drafts", draft)
    assert r.status_code == 200
    draft_resp = json.loads(r.data)
    assert attachment_id in [x["id"] for x in draft_resp["files"]]
Example #41
0
def test_api_create(db, api_client, calendar, default_account):
    e_data = {
        'title': 'Friday Office Party',
        'calendar_id': calendar.public_id,
        'when': {
            'time': 1407542195
        },
        'location': 'Nylas HQ',
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data['object'] == 'event'
    assert e_resp_data['account_id'] == default_account.namespace.public_id
    assert e_resp_data['title'] == e_data['title']
    assert e_resp_data['location'] == e_data['location']
    assert e_resp_data['when']['time'] == e_data['when']['time']
    assert 'id' in e_resp_data
    e_id = e_resp_data['id']
    e_get_resp = api_client.get_data('/events/' + e_id)

    assert e_get_resp['object'] == 'event'
    assert e_get_resp['account_id'] == default_account.namespace.public_id
    assert e_get_resp['id'] == e_id
    assert e_get_resp['title'] == e_data['title']
    assert e_get_resp['when']['time'] == e_data['when']['time']
Example #42
0
def test_multisend_handle_recipients_rejected(recipients_refused, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data('/send-multiple/' + multisend['id'],
                             multisend['send_req'])
    assert r.status_code == 402
    assert json.loads(r.data)['message'] == 'Sending to all recipients failed'
Example #43
0
def test_api_update_title(db, api_client, calendar, default_account):
    e_data = {
        'title': '',
        'calendar_id': calendar.public_id,
        'when': {'time': 1407542195},
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data['object'] == 'event'
    assert e_resp_data['account_id'] == default_account.namespace.public_id
    assert e_resp_data['title'] == e_data['title']
    assert e_resp_data['when']['time'] == e_data['when']['time']
    assert 'id' in e_resp_data
    e_id = e_resp_data['id']

    e_update_data = {'title': 'new title'}
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data)
    e_put_data = json.loads(e_put_resp.data)

    assert e_put_data['object'] == 'event'
    assert e_put_data['account_id'] == default_account.namespace.public_id
    assert e_put_data['id'] == e_id
    assert e_put_data['title'] == 'new title'
    assert e_put_data['when']['object'] == 'time'
    assert e_put_data['when']['time'] == e_data['when']['time']
Example #44
0
def test_rsvp_idempotent(db, patch_smtp, api_client, example_rsvp,
                         imported_event, status, comment):
    part = imported_event.participants[0]
    part['status'] = status
    part['comment'] = comment

    # MutableList shenanigans -- it won't update
    # what's stored in the db otherwise.
    imported_event.participants = []
    db.session.commit()

    imported_event.participants = [part]
    db.session.commit()

    old_update_date = imported_event.updated_at
    db.session.expunge(imported_event)

    rsvp = {'event_id': imported_event.public_id,
            'status': status, 'comment': comment}
    r = api_client.post_data('/send-rsvp', rsvp)
    assert r.status_code == 200
    dct = json.loads(r.data)

    # check that the event's status is the same.
    assert len(dct['participants']) == 1
    assert dct['participants'][0]['email'] == '*****@*****.**'
    assert dct['participants'][0]['status'] == status

    assert dct['participants'][0]['comment'] == comment

    # Check that the event hasn't been updated.
    refreshed_event = db.session.query(Event).get(imported_event.id)
    assert refreshed_event.updated_at == old_update_date
Example #45
0
def test_malformed_subject_rejected(api_client, example_draft_bad_subject):
    r = api_client.post_data('/send', example_draft_bad_subject)
    assert r.status_code == 400

    decoded = json.loads(r.get_data())
    assert decoded['type'] == 'invalid_request_error'
    assert decoded['message'] == '"subject" should be a string'
Example #46
0
def test_delete_draft(api_client, thread, message):
    original_draft = {"subject": "parent draft", "body": "parent draft"}
    r = api_client.post_data("/drafts", original_draft)
    draft_public_id = json.loads(r.data)["id"]
    version = json.loads(r.data)["version"]

    updated_draft = {
        "subject": "updated draft",
        "body": "updated draft",
        "version": version,
    }
    r = api_client.put_data("/drafts/{}".format(draft_public_id),
                            updated_draft)
    updated_public_id = json.loads(r.data)["id"]
    updated_version = json.loads(r.data)["version"]

    r = api_client.delete("/drafts/{}".format(updated_public_id),
                          {"version": updated_version})

    # Check that drafts were deleted
    drafts = api_client.get_data("/drafts")
    assert not drafts

    # Check that no orphaned threads are around
    threads = api_client.get_data("/threads?subject=parent%20draft")
    assert not threads
    threads = api_client.get_data("/threads?subject=updated%20draft")
    assert not threads

    # And check that threads aren't deleted if they still have messages.
    thread_public_id = api_client.get_data("/threads")[0]["id"]

    reply_draft = {
        "subject": "test reply",
        "body": "test reply",
        "thread_id": thread_public_id,
    }
    r = api_client.post_data("/drafts", reply_draft)
    public_id = json.loads(r.data)["id"]
    version = json.loads(r.data)["version"]
    thread = api_client.get_data("/threads/{}".format(thread_public_id))
    assert len(thread["draft_ids"]) > 0
    api_client.delete("/drafts/{}".format(public_id), {"version": version})
    thread = api_client.get_data("/threads/{}".format(thread_public_id))
    assert thread
    assert len(thread["draft_ids"]) == 0
Example #47
0
def test_delete_draft(api_client, thread, message):
    original_draft = {'subject': 'parent draft', 'body': 'parent draft'}
    r = api_client.post_data('/drafts', original_draft)
    draft_public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']

    updated_draft = {
        'subject': 'updated draft',
        'body': 'updated draft',
        'version': version
    }
    r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                            updated_draft)
    updated_public_id = json.loads(r.data)['id']
    updated_version = json.loads(r.data)['version']

    r = api_client.delete('/drafts/{}'.format(updated_public_id),
                          {'version': updated_version})

    # Check that drafts were deleted
    drafts = api_client.get_data('/drafts')
    assert not drafts

    # Check that no orphaned threads are around
    threads = api_client.get_data('/threads?subject=parent%20draft')
    assert not threads
    threads = api_client.get_data('/threads?subject=updated%20draft')
    assert not threads

    # And check that threads aren't deleted if they still have messages.
    thread_public_id = api_client.get_data('/threads')[0]['id']

    reply_draft = {
        'subject': 'test reply',
        'body': 'test reply',
        'thread_id': thread_public_id
    }
    r = api_client.post_data('/drafts', reply_draft)
    public_id = json.loads(r.data)['id']
    version = json.loads(r.data)['version']
    thread = api_client.get_data('/threads/{}'.format(thread_public_id))
    assert len(thread['draft_ids']) > 0
    api_client.delete('/drafts/{}'.format(public_id), {'version': version})
    thread = api_client.get_data('/threads/{}'.format(thread_public_id))
    assert thread
    assert len(thread['draft_ids']) == 0
Example #48
0
def test_multisend_handle_invalid_credentials(disallow_auth, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data('/send-multiple/' + multisend['id'],
                             multisend['send_req'])
    assert r.status_code == 403
    assert json.loads(r.data)['message'] == 'Could not authenticate with ' \
                                            'the SMTP server.'
Example #49
0
def test_multisend_handle_server_disconnected(connection_closed, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data('/send-multiple/' + multisend['id'],
                             multisend['send_req'])
    assert r.status_code == 503
    assert json.loads(r.data)['message'] == 'The server unexpectedly closed ' \
                                            'the connection'
Example #50
0
def test_multisend_message_rejected_for_security(insecure_content, api_client,
                                                 multisend,
                                                 patch_crispin_del_sent):
    r = api_client.post_data('/send-multiple/' + multisend['id'],
                             multisend['send_req'])
    assert r.status_code == 402
    assert json.loads(r.data)['message'] == 'Message content rejected ' \
                                            'for security reasons'
Example #51
0
def test_multisend_handle_server_disconnected(connection_closed, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data("/send-multiple/" + multisend["id"],
                             multisend["send_req"])
    assert r.status_code == 503
    assert (json.loads(r.data)["message"] == "The server unexpectedly closed "
            "the connection")
Example #52
0
def test_multisend_message_rejected_for_security(insecure_content, api_client,
                                                 multisend,
                                                 patch_crispin_del_sent):
    r = api_client.post_data("/send-multiple/" + multisend["id"],
                             multisend["send_req"])
    assert r.status_code == 402
    assert (json.loads(r.data)["message"] == "Message content rejected "
            "for security reasons")
Example #53
0
def test_smtp_ssl_verification_bad_cert(db, bad_cert_smtp_server,
                                        example_draft, local_smtp_account,
                                        api_client, patched_smtp):

    api_client = new_api_client(db, local_smtp_account.namespace)
    gevent.sleep(0.2)  # let SMTP daemon start up
    r = api_client.post_data('/send', example_draft)
    assert r.status_code == 200
Example #54
0
def test_malformed_body_rejected(api_client, example_draft_bad_body):
    r = api_client.post_data("/send", example_draft_bad_body)

    assert r.status_code == 400

    decoded = json.loads(r.get_data())
    assert decoded["type"] == "invalid_request_error"
    assert decoded["message"] == '"body" should be a string'
Example #55
0
def test_multisend_init_malformed_subject_rejected(api_client,
                                                   example_draft_bad_subject):
    r = api_client.post_data("/send-multiple", example_draft_bad_subject)
    assert r.status_code == 400

    decoded = json.loads(r.get_data())
    assert decoded["type"] == "invalid_request_error"
    assert decoded["message"] == '"subject" should be a string'
Example #56
0
def test_multisend_handle_invalid_credentials(disallow_auth, api_client,
                                              multisend,
                                              patch_crispin_del_sent):
    r = api_client.post_data("/send-multiple/" + multisend["id"],
                             multisend["send_req"])
    assert r.status_code == 403
    assert (json.loads(r.data)["message"] == "Could not authenticate with "
            "the SMTP server.")
Example #57
0
def test_sending_from_email_alias(patch_smtp, api_client):
    api_client.post_data(
        '/send', {
            'to': [{
                'email': '*****@*****.**'
            }],
            'from': [{
                'name': 'admin',
                'email': '*****@*****.**'
            }],
            'subject': 'Banalities',
            'body': '<html>Hello there</html>'
        })
    _, msg = patch_smtp[-1]
    parsed = mime.from_string(msg)
    assert 'From' in parsed.headers
    assert parsed.headers['From'] == 'admin <*****@*****.**>'
Example #58
0
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = '/files'
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.post_raw(upload_path, data=data)
        assert r.status_code == 200
        attachment_id = json.loads(r.data)[0]['id']
        attachment_ids.append(attachment_id)

    first_attachment = attachment_ids.pop()

    example_draft['file_ids'] = [first_attachment]
    r = api_client.post_data('/drafts', example_draft)
    assert r.status_code == 200
    returned_draft = json.loads(r.data)
    draft_public_id = returned_draft['id']
    assert returned_draft['version'] == 0
    example_draft['version'] = returned_draft['version']
    assert len(returned_draft['files']) == 1

    attachment_ids.append(first_attachment)
    example_draft['file_ids'] = attachment_ids
    r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                            example_draft)
    assert r.status_code == 200
    returned_draft = json.loads(r.data)
    assert len(returned_draft['files']) == 3
    assert returned_draft['version'] == 1
    example_draft['version'] = returned_draft['version']

    # Make sure we can't delete the files now
    for file_id in attachment_ids:
        r = api_client.delete('/files/{}'.format(file_id))
        assert r.status_code == 400

    # Now remove the attachment
    example_draft['file_ids'] = [first_attachment]
    r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                            example_draft)

    draft_data = api_client.get_data('/drafts/{}'.format(draft_public_id))
    assert len(draft_data['files']) == 1
    assert draft_data['version'] == 2
    example_draft['version'] = draft_data['version']

    example_draft['file_ids'] = []
    r = api_client.put_data('/drafts/{}'.format(draft_public_id),
                            example_draft)
    draft_data = api_client.get_data('/drafts/{}'.format(draft_public_id))
    assert r.status_code == 200
    assert len(draft_data['files']) == 0
    assert draft_data['version'] == 3

    # now that they're not attached, we should be able to delete them
    for file_id in attachment_ids:
        r = api_client.delete('/files/{}'.format(file_id))
        assert r.status_code == 200
Example #59
0
def test_invalid_input(api_client):
    cursor_response = api_client.post_data('/delta/generate_cursor',
                                           {'start': "I'm not a timestamp!"})
    assert cursor_response.status_code == 400

    sync_response = api_client.client.get(
        '/delta?cursor={}'.format('fake cursor'),
        headers=api_client.auth_header)
    assert sync_response.status_code == 400
Example #60
0
def test_multisend_init_malformed_body_rejected(api_client,
                                                example_draft_bad_body):
    r = api_client.post_data('/send-multiple', example_draft_bad_body)

    assert r.status_code == 400

    decoded = json.loads(r.get_data())
    assert decoded['type'] == 'invalid_request_error'
    assert decoded['message'] == '"body" should be a string'