def test_expanded_message(stub_message, api_client):
    def _check_json_message(msg_dict):
        assert 'body' in msg_dict
        assert msg_dict['object'] == 'message'
        assert msg_dict['thread_id'] == stub_message.thread.public_id

        assert isinstance(msg_dict['headers'], dict)
        assert 'In-Reply-To' in msg_dict['headers']
        assert 'References' in msg_dict['headers']
        assert 'Message-Id' in msg_dict['headers']

        valid_keys = ['namespace_id', 'to', 'from', 'files', 'unread',
                      'unread', 'date', 'snippet']
        assert all(x in msg_dict for x in valid_keys)

    # /message/<message_id>
    resp = api_client.client.get(api_client.full_path(
        '/messages/{}?view=expanded'.format(stub_message.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)
    _check_json_message(resp_dict)

    # /messages/
    resp = api_client.client.get(api_client.full_path(
        '/messages/?view=expanded'))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)

    for message_json in resp_dict:
        if message_json['id'] == stub_message.public_id:
            _check_json_message(message_json)
Beispiel #2
0
def test_thread_received_recent_date(db, api_client, default_account):
    date1 = datetime.datetime(2015, 1, 1, 0, 0, 0)
    date2 = datetime.datetime(2012, 1, 1, 0, 0, 0)

    thread1 = add_fake_thread(db.session, default_account.namespace.id)

    date_dict = dict()

    add_fake_message(db.session, default_account.namespace.id, thread1,
                     subject="Test Thread 1", received_date=date1,
                     add_sent_category=True)
    add_fake_message(db.session, default_account.namespace.id, thread1,
                     subject="Test Thread 1", received_date=date2)

    date_dict["Test Thread 1"] = date2

    thread2 = add_fake_thread(db.session, default_account.namespace.id)
    add_fake_message(db.session, default_account.namespace.id, thread2,
                     subject="Test Thread 2", received_date=date1,
                     add_sent_category=True)

    date_dict["Test Thread 2"] = date1

    resp = api_client.client.get(api_client.full_path('/threads/'))
    assert resp.status_code == 200
    threads = json.loads(resp.data)

    for thread in threads:
        assert date_dict[thread['subject']] == \
            datetime.datetime.fromtimestamp(
                thread['last_message_received_timestamp'])
Beispiel #3
0
def test_expanded_threads(stub_message, api_client):
    def _check_json_thread(resp_dict):
        assert 'message_ids' not in resp_dict
        assert 'messages' in resp_dict
        assert 'drafts' in resp_dict
        assert len(resp_dict['participants']) == 3
        assert len(resp_dict['messages']) == 2
        assert len(resp_dict['drafts']) == 1

        for msg_dict in resp_dict['messages']:
            assert 'body' not in msg_dict
            assert msg_dict['object'] == 'message'
            assert msg_dict['thread_id'] == stub_message.thread.public_id
            valid_keys = [
                'namespace_id', 'to', 'from', 'files', 'unread', 'unread',
                'date', 'snippet'
            ]
            assert all(x in msg_dict for x in valid_keys)

        for draft in resp_dict['drafts']:
            assert 'body' not in draft
            assert draft['object'] == 'draft'
            assert draft['thread_id'] == stub_message.thread.public_id
            valid_keys = [
                'namespace_id', 'to', 'from', 'files', 'unread', 'snippet',
                'date', 'version', 'reply_to_message_id'
            ]
            assert all(x in draft for x in valid_keys)

    # /threads/<thread_id>
    resp = api_client.client.get(
        api_client.full_path('/threads/{}?view=expanded'.format(
            stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)
    _check_json_thread(resp_dict)

    # /threads/
    resp = api_client.client.get(
        api_client.full_path('/threads/?view=expanded'.format(
            stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)

    for thread_json in resp_dict:
        if thread_json['id'] == stub_message.thread.public_id:
            _check_json_thread(thread_json)
def test_rfc822_format(stub_message_from_raw, api_client, mime_message):
    """ Test the API response to retreive raw message contents """
    full_path = api_client.full_path('/messages/{}'.format(
        stub_message_from_raw.public_id))

    results = api_client.client.get(full_path,
                                    headers={'Accept': 'message/rfc822'})
    assert results.data == mime_message.to_string()
Beispiel #5
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(api_client.full_path(
        '/delta?cursor={}'.format('fake cursor'), 1))
    assert sync_response.status_code == 400
Beispiel #6
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(
        api_client.full_path('/delta?cursor={}'.format('fake cursor'), 1))
    assert sync_response.status_code == 400
Beispiel #7
0
def test_invalid_input(api_client):
    stamp_response = api_client.post_data('/sync/generate_stamp',
                                          {'start': "I'm not a timestamp!"})
    assert stamp_response.status_code == 400

    sync_response = api_client.client.get(api_client.full_path(
        '/sync/events?stamp={}'.format('fake stamp'), 1))
    assert sync_response.status_code == 404
def test_rfc822_format(stub_message_from_raw, api_client, raw_message):
    """ Test the API response to retreive raw message contents """
    full_path = api_client.full_path('/messages/{}'.format(
        stub_message_from_raw.public_id))

    results = api_client.client.get(full_path,
                                    headers={'Accept': 'message/rfc822'})
    assert results.data == raw_message
Beispiel #9
0
def test_rfc822_format(stub_message_from_raw, api_client):
    """ Test the API response to retreive raw message contents """
    full_path = api_client.full_path('/messages/{}'.format(
        stub_message_from_raw.public_id),
        ns_id=stub_message_from_raw.namespace_id)

    results = api_client.client.get(full_path,
                                    headers={'Accept': 'message/rfc822'})
    assert results.data == raw_message()
def test_sender_and_participants(stub_message, api_client):
    resp = api_client.client.get(api_client.full_path(
        '/threads/{}'.format(stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)
    participants = resp_dict['participants']
    assert len(participants) == 3

    # Not expanded, should only return IDs
    assert 'message' not in resp_dict
    assert 'drafts' not in resp_dict
Beispiel #11
0
def uploaded_file_ids(api_client, files):
    file_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in files:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(upload_path, data=data)
        assert r.status_code == 200
        file_id = json.loads(r.data)[0]['id']
        file_ids.append(file_id)

    return file_ids
def test_sender_and_participants(stub_message, api_client):
    resp = api_client.client.get(api_client.full_path(
        '/threads/{}'.format(stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)
    participants = resp_dict['participants']
    assert len(participants) == 3

    # Not expanded, should only return IDs
    assert 'message' not in resp_dict
    assert 'drafts' not in resp_dict
Beispiel #13
0
def uploaded_file_ids(api_client, files):
    file_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in files:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(upload_path, data=data)
        assert r.status_code == 200
        file_id = json.loads(r.data)[0]['id']
        file_ids.append(file_id)

    return file_ids
def test_expanded_threads(stub_message, api_client):
    def _check_json_thread(resp_dict):
        assert 'message_ids' not in resp_dict
        assert 'messages' in resp_dict
        assert 'drafts' in resp_dict
        assert len(resp_dict['participants']) == 3
        assert len(resp_dict['messages']) == 2
        assert len(resp_dict['drafts']) == 1

        for msg_dict in resp_dict['messages']:
            assert 'body' not in msg_dict
            assert msg_dict['object'] == 'message'
            assert msg_dict['thread_id'] == stub_message.thread.public_id
            valid_keys = ['namespace_id', 'to', 'from', 'files', 'unread',
                          'unread', 'date', 'snippet']
            assert all(x in msg_dict for x in valid_keys)

        for draft in resp_dict['drafts']:
            assert 'body' not in draft
            assert draft['object'] == 'draft'
            assert draft['thread_id'] == stub_message.thread.public_id
            valid_keys = ['namespace_id', 'to', 'from', 'files', 'unread',
                          'snippet', 'date', 'version', 'reply_to_message_id']
            assert all(x in draft for x in valid_keys)

    # /threads/<thread_id>
    resp = api_client.client.get(api_client.full_path(
        '/threads/{}?view=expanded'.format(stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)
    _check_json_thread(resp_dict)

    # /threads/
    resp = api_client.client.get(api_client.full_path(
        '/threads/?view=expanded'.format(stub_message.thread.public_id)))
    assert resp.status_code == 200
    resp_dict = json.loads(resp.data)

    for thread_json in resp_dict:
        if thread_json['id'] == stub_message.thread.public_id:
            _check_json_thread(thread_json)
def test_rfc822_format(db, api_client, default_namespace, raw_message):
    """ Test the API response to retreive raw message contents """
    namespace_id = default_namespace.id
    new_msg = new_message_from_synced(db, default_namespace.account, raw_message)
    fake_thread = add_fake_thread(db.session, namespace_id)
    new_msg.thread = fake_thread
    db.session.add_all([new_msg, fake_thread])
    db.session.commit()

    full_path = api_client.full_path('/messages/{}'.format(new_msg.public_id))

    results = api_client.client.get(full_path,
                                    headers={'Accept': 'message/rfc822'})

    assert results.data == raw_message
def test_rfc822_format(db, api_client, new_message_from_synced):
    """ Test the API response to retreive raw message contents """
    NAMESPACE_ID = default_namespace(db).id
    new_msg = new_message_from_synced
    fake_thread = add_fake_thread(db.session, NAMESPACE_ID)
    new_msg.thread = fake_thread
    db.session.add_all([new_msg, fake_thread])
    db.session.commit()

    full_path = api_client.full_path('/messages/{}'.format(new_msg.public_id),
                                     ns_id=NAMESPACE_ID)

    results = api_client.client.get(full_path,
                                    headers={'Accept': 'message/rfc822'})

    assert results.data == raw_message()
Beispiel #17
0
def uploaded_file_ids(api_client, files):
    file_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in files:
        # Mac and linux fight over filesystem encodings if we store this
        # filename on the fs. Work around by changing the filename we upload
        # instead.
        if filename == 'piece-jointe.jpg':
            filename = u'pièce-jointe.jpg'
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(upload_path, data=data)
        assert r.status_code == 200
        file_id = json.loads(r.data)[0]['id']
        file_ids.append(file_id)

    return file_ids
Beispiel #18
0
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(upload_path, data=data)
        assert r.status_code == 200
        attachment_id = json.loads(r.data)[0]['id']
        attachment_ids.append(attachment_id)

    example_draft['files'] = attachment_ids
    r = api_client.post_data('/drafts', example_draft)
    assert r.status_code == 200

    threads_with_drafts = api_client.get_data('/threads?tag=drafts')
    assert len(threads_with_drafts) == 1

    # Check that thread also gets the attachment tag
    thread_tags = threads_with_drafts[0]['tags']
    assert any('attachment' == tag['name'] for tag in thread_tags)
Beispiel #19
0
def test_thread_received_recent_date(db, api_client, default_account):
    date1 = datetime.datetime(2015, 1, 1, 0, 0, 0)
    date2 = datetime.datetime(2012, 1, 1, 0, 0, 0)

    thread1 = add_fake_thread(db.session, default_account.namespace.id)

    date_dict = dict()

    add_fake_message(db.session,
                     default_account.namespace.id,
                     thread1,
                     subject="Test Thread 1",
                     received_date=date1,
                     add_sent_category=True)
    add_fake_message(db.session,
                     default_account.namespace.id,
                     thread1,
                     subject="Test Thread 1",
                     received_date=date2)

    date_dict["Test Thread 1"] = date2

    thread2 = add_fake_thread(db.session, default_account.namespace.id)
    add_fake_message(db.session,
                     default_account.namespace.id,
                     thread2,
                     subject="Test Thread 2",
                     received_date=date1,
                     add_sent_category=True)

    date_dict["Test Thread 2"] = date1

    resp = api_client.client.get(api_client.full_path('/threads/'))
    assert resp.status_code == 200
    threads = json.loads(resp.data)

    for thread in threads:
        assert date_dict[thread['subject']] == \
            datetime.datetime.fromtimestamp(
                thread['last_message_received_timestamp'])
Beispiel #20
0
def test_strict_argument_parsing(api_client):
    r = api_client.client.get(api_client.full_path('/threads?foo=bar'))
    assert r.status_code == 400
def test_contact_rankings(db, api_client, default_namespace):
    # Clear cached data (if it exists)
    namespace_id = default_namespace.id
    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        cached_data.contact_rankings_last_updated = None
        db.session.add(cached_data)
        db.session.commit()
    except NoResultFound:
        pass

    # Send some emails
    namespace_email = default_namespace.email_address

    me = ('me', namespace_email)
    recipients = ([[('first', '*****@*****.**')]] * 8 +
                  [[('second', '*****@*****.**')]] * 4 +
                  [[('third', '*****@*****.**')]] +
                  [[('third', '*****@*****.**'),
                    ('fourth', '*****@*****.**')]])

    for recipients_list in recipients:
        fake_thread = add_fake_thread(db.session, namespace_id)
        add_fake_message(db.session,
                         namespace_id,
                         fake_thread,
                         subject='Froop',
                         from_addr=[me],
                         to_addr=recipients_list,
                         add_sent_category=True)

    # Check contact rankings
    resp = api_client.client.get(
        api_client.full_path('/contacts/rankings?force_recalculate=true'))
    assert resp.status_code == 200

    emails_scores = {e: s for (e, s) in json.loads(resp.data)}
    emails = [
        '*****@*****.**', '*****@*****.**', '*****@*****.**',
        '*****@*****.**'
    ]
    for email in emails:
        assert email in emails_scores

    for e1, e2 in zip(emails, emails[1:]):
        assert emails_scores[e1] > emails_scores[e2]

    # make sure it works if we call it again!
    resp = api_client.client.get(api_client.full_path('/contacts/rankings'))
    assert resp.status_code == 200

    emails_scores = {e: s for (e, s) in json.loads(resp.data)}
    emails = [
        '*****@*****.**', '*****@*****.**', '*****@*****.**',
        '*****@*****.**'
    ]
    for email in emails:
        assert email in emails_scores

    for e1, e2 in zip(emails, emails[1:]):
        assert emails_scores[e1] > emails_scores[e2]

    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        assert cached_data.contact_rankings_last_updated is not None
    except (NoResultFound, AssertionError):
        assert False, "Contact rankings not cached"
Beispiel #22
0
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(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']
    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
    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

    threads_with_drafts = api_client.get_data('/threads?tag=drafts')
    assert len(threads_with_drafts) == 1

    # Check that thread also gets the attachment tag
    thread_tags = threads_with_drafts[0]['tags']
    assert any('attachment' == tag['name'] for tag in thread_tags)

    # 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
    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
    returned_draft = json.loads(r.data)

    # 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
Beispiel #23
0
def test_strict_argument_parsing(api_client):
    r = api_client.client.get(api_client.full_path('/threads?foo=bar'))
    assert r.status_code == 400
def test_contact_rankings(db, api_client, default_namespace):
    # Clear cached data (if it exists)
    namespace_id = default_namespace.id
    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        cached_data.contact_rankings_last_updated = None
        db.session.add(cached_data)
        db.session.commit()
    except NoResultFound:
        pass

    # Send some emails
    namespace_email = default_namespace.email_address

    me = ('me', namespace_email)
    recipients = ([[('first', '*****@*****.**')]] * 8 +
                  [[('second', '*****@*****.**')]] * 4 +
                  [[('third', '*****@*****.**')]] +
                  [[('third', '*****@*****.**'),
                    ('fourth', '*****@*****.**')]])

    for recipients_list in recipients:
        fake_thread = add_fake_thread(db.session, namespace_id)
        add_fake_message(db.session, namespace_id, fake_thread,
                         subject='Froop',
                         from_addr=[me],
                         to_addr=recipients_list,
                         add_sent_category=True)

    # Check contact rankings
    resp = api_client.client.get(api_client.full_path(
        '/contacts/rankings?force_recalculate=true'))
    assert resp.status_code == 200

    emails_scores = {e: s for (e, s) in json.loads(resp.data)}
    emails = ['*****@*****.**', '*****@*****.**',
              '*****@*****.**', '*****@*****.**']
    for email in emails:
        assert email in emails_scores

    for e1, e2 in zip(emails, emails[1:]):
        assert emails_scores[e1] > emails_scores[e2]

    # make sure it works if we call it again!
    resp = api_client.client.get(api_client.full_path(
        '/contacts/rankings'))
    assert resp.status_code == 200

    emails_scores = {e: s for (e, s) in json.loads(resp.data)}
    emails = ['*****@*****.**', '*****@*****.**',
              '*****@*****.**', '*****@*****.**']
    for email in emails:
        assert email in emails_scores

    for e1, e2 in zip(emails, emails[1:]):
        assert emails_scores[e1] > emails_scores[e2]

    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        assert cached_data.contact_rankings_last_updated is not None
    except (NoResultFound, AssertionError):
        assert False, "Contact rankings not cached"
def test_contact_groups(db, api_client, default_namespace):
    # Clear cached data (if it exists)
    namespace_id = default_namespace.id
    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        cached_data.contact_groups_last_updated = None
        db.session.add(cached_data)
        db.session.commit()
    except NoResultFound:
        pass

    # Send some emails
    namespace_email = default_namespace.email_address
    me = ('me', namespace_email)
    recipients = ([[('a', '*****@*****.**'),
                   ('b', '*****@*****.**'),
                   ('c', '*****@*****.**')]] * 8 +
                  [[('b', '*****@*****.**'),
                     ('c', '*****@*****.**'),
                     ('d', '*****@*****.**')]] * 8 +
                  [[('d', '*****@*****.**'),
                     ('e', '*****@*****.**'),
                     ('f', '*****@*****.**')]] * 8 +
                  [[('g', '*****@*****.**'),
                     ('h', '*****@*****.**'),
                     ('i', '*****@*****.**'),
                     ('j', '*****@*****.**')]] * 5 +
                   [[('g', '*****@*****.**'),
                     ('h', '*****@*****.**'),
                     ('i', '*****@*****.**')]] * 2 +
                  [[('k', '*****@*****.**'),
                     ('l', '*****@*****.**')]] * 3)

    for recipients_list in recipients:
        fake_thread = add_fake_thread(db.session, namespace_id)
        add_fake_message(db.session, namespace_id, fake_thread,
                         subject='Froop',
                         from_addr=[me],
                         to_addr=recipients_list,
                         add_sent_category=True)

    # Check contact groups
    resp = api_client.client.get(api_client.full_path(
        '/groups/intrinsic?force_recalculate=true'))
    assert resp.status_code == 200

    groups_scores = {g: s for (g, s) in json.loads(resp.data)}
    groups = ['[email protected], [email protected], [email protected], [email protected]',
              '[email protected], [email protected], [email protected]',
              '[email protected], [email protected], [email protected], [email protected]',
              '[email protected], [email protected]']
    for g in groups:
        assert g in groups_scores

    # make sure it works when we do it again
    resp = api_client.client.get(api_client.full_path(
        '/groups/intrinsic'))
    assert resp.status_code == 200

    groups_scores = {g: s for (g, s) in json.loads(resp.data)}
    for g in groups:
        assert g in groups_scores

    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        assert cached_data.contact_groups_last_updated is not None
    except (NoResultFound, AssertionError):
        assert False, "Contact groups not cached"
Beispiel #26
0
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = api_client.full_path('/files')
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.client.post(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']
    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
    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

    threads_with_drafts = api_client.get_data('/threads?tag=drafts')
    assert len(threads_with_drafts) == 1

    # Check that thread also gets the attachment tag
    thread_tags = threads_with_drafts[0]['tags']
    assert any('attachment' == tag['name'] for tag in thread_tags)

    # 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
    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
    returned_draft = json.loads(r.data)

    # 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
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = api_client.full_path("/files")
    for filename, path in attachments:
        data = {"file": (open(path, "rb"), filename)}
        r = api_client.client.post(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

    threads_with_drafts = api_client.get_data("/threads?tag=drafts")
    assert len(threads_with_drafts) == 1

    # Check that thread also gets the attachment tag
    thread_tags = threads_with_drafts[0]["tags"]
    assert any("attachment" == tag["name"] for tag in thread_tags)

    # 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
def test_contact_groups(db, api_client, default_namespace):
    # Clear cached data (if it exists)
    namespace_id = default_namespace.id
    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        cached_data.contact_groups_last_updated = None
        db.session.add(cached_data)
        db.session.commit()
    except NoResultFound:
        pass

    # Send some emails
    namespace_email = default_namespace.email_address
    me = ('me', namespace_email)
    recipients = ([[('a', '*****@*****.**'), ('b', '*****@*****.**'),
                    ('c', '*****@*****.**')]] * 8 + [[('b', '*****@*****.**'),
                                                   ('c', '*****@*****.**'),
                                                   ('d', '*****@*****.**')]] * 8 +
                  [[('d', '*****@*****.**'), ('e', '*****@*****.**'),
                    ('f', '*****@*****.**')]] * 8 + [[('g', '*****@*****.**'),
                                                   ('h', '*****@*****.**'),
                                                   ('i', '*****@*****.**'),
                                                   ('j', '*****@*****.**')]] * 5 +
                  [[('g', '*****@*****.**'), ('h', '*****@*****.**'),
                    ('i', '*****@*****.**')]] * 2 + [[('k', '*****@*****.**'),
                                                   ('l', '*****@*****.**')]] * 3)

    for recipients_list in recipients:
        fake_thread = add_fake_thread(db.session, namespace_id)
        add_fake_message(db.session,
                         namespace_id,
                         fake_thread,
                         subject='Froop',
                         from_addr=[me],
                         to_addr=recipients_list,
                         add_sent_category=True)

    # Check contact groups
    resp = api_client.client.get(
        api_client.full_path('/groups/intrinsic?force_recalculate=true'))
    assert resp.status_code == 200

    groups_scores = {g: s for (g, s) in json.loads(resp.data)}
    groups = [
        '[email protected], [email protected], [email protected], [email protected]',
        '[email protected], [email protected], [email protected]',
        '[email protected], [email protected], [email protected], [email protected]',
        '[email protected], [email protected]'
    ]
    for g in groups:
        assert g in groups_scores

    # make sure it works when we do it again
    resp = api_client.client.get(api_client.full_path('/groups/intrinsic'))
    assert resp.status_code == 200

    groups_scores = {g: s for (g, s) in json.loads(resp.data)}
    for g in groups:
        assert g in groups_scores

    try:
        cached_data = db.session.query(DataProcessingCache) \
                      .filter(DataProcessingCache.namespace_id ==
                              namespace_id).one()
        assert cached_data.contact_groups_last_updated is not None
    except (NoResultFound, AssertionError):
        assert False, "Contact groups not cached"