예제 #1
0
    def test_dummy(self):
        from orgs.example_org.ExampleOrg import signature
        email_service = Mock()
        all_threads = [Thread(*get_thread_constructor_args('integration_test_inputs/one_email_thread.txt'), email_service)]
        email_service.query = MagicMock(return_value=all_threads)
        email_service.get_label_name = MagicMock(return_value='Schools')
        email_service.set_label = MagicMock(return_value={'labelIds' : ['test label id']})
        email_service.get_all_history_ids = MagicMock(return_value={})
        email_service.get_user = MagicMock(return_value='tyler')
        email_service.get_email = MagicMock(return_value='*****@*****.**')
        email_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])
        draft_id = '1234'
        draft_msg_id = '2345'
        email_service.get_drafts = MagicMock(return_value=[{'id' : draft_id, 'message' : {'id' : draft_msg_id}}])
        email_service.append_or_create_draft = MagicMock(return_value=GMailMessage({'id' : draft_msg_id, 'snippet' : signature(all_threads[0]), 'labelIds' : ['DRAFT'], 'payload' : {'body' : { 'data' : encode_for_payload(signature(all_threads[0]))}, 'headers' : [{'name' : 'to', 'value' : 'Tyler Galdes <*****@*****.**>'}]}}, {}))
        email_service.send_draft = MagicMock(return_value=GMailMessage({'id' : draft_msg_id, 'snippet' : signature(all_threads[0]), 'labelIds' : ['SENT'], 'payload' : {'body' : { 'data' : encode_for_payload(signature(all_threads[0]))}, 'headers' : [{'name' : 'to', 'value' : 'Tyler Galdes <*****@*****.**>'}]}}, {}))
        config = {}
        config['org'] = {}
        config['org']['name'] = 'example_org'
        config['org']['imports'] = ['from orgs.example_org.ExampleOrg import signature']
        config['org_init_import'] = 'from orgs.example_org.ExampleOrg import org_init'
        logger = Logger('TestIntegration')
        m = Main([email_service], logger, config)

        m.setup()
        m.run_one()

        # We'll process one email, add a label, and add a greeting and signature as a draft based on that label
        self.assertTrue('Schools' in all_threads[0].labels())
        self.assertTrue(all_threads[0].has_draft())
        # We'll look at the MimeMultipart we got on the last call to append_or_create_draft and confirm it's content
        mime_multipart, thread_id, called_draft_id = email_service.append_or_create_draft.call_args[0]

        self.assertEqual(all_threads[0].identifier, thread_id)
        self.assertEqual(draft_id, called_draft_id)
        self.assertEqual('*****@*****.**', mime_multipart['from'])
        self.assertEqual('*****@*****.**', mime_multipart['to'])
        self.assertEqual('test subject', mime_multipart['subject'])
        self.assertEqual('<CACUCK-BGnDjQ6QzU0cGKwLpHOnJoseTVjR1CNQ+yEubty=ar9A@mail.gmail.com>', mime_multipart['In-Reply-To'])
        self.assertEqual('<CACUCK-BGnDjQ6QzU0cGKwLpHOnJoseTVjR1CNQ+yEubty=ar9A@mail.gmail.com>', mime_multipart['References'])
        self.assertEqual(all_threads[0].salutation() + signature(all_threads[0]), mime_multipart.__dict__['_payload'][0].__dict__['_payload'])

        # now let's send the draft that we created
        self.assertEqual(1, len(all_threads[0])) # len doesn't count draft messages
        all_threads[0].send_draft()
        self.assertFalse(all_threads[0].has_draft())
        self.assertEqual(2, len(all_threads[0]))
        sent_draft_id = email_service.send_draft.call_args[0][0]
        self.assertEqual(draft_id, sent_draft_id)
예제 #2
0
    def append_or_create_draft(self,
                               mime_email,
                               thread_id,
                               draft_id=None,
                               userId='me'):
        payload = {
            'message': {
                'threadId':
                thread_id,
                'raw':
                base64.urlsafe_b64encode(
                    mime_email.as_string().encode('utf-8')).decode()
            }
        }
        # update an existing draft
        if draft_id:
            draft = self.service.users().drafts().update(
                userId=userId, id=draft_id, body=payload).execute()
            self.li('Appended to existing draft with id: {}'.format(draft_id))


# create a new draft!
        else:
            draft = self.service.users().drafts().create(
                userId=userId, body=payload).execute()
            self.li('Created new draft with id: {}'.format(draft['id']))
        self.__update_drafts(draft)
        message_data = self.service.users().messages().get(
            userId=userId, id=draft['message']['id']).execute()
        self.__update_history_id(message_data['threadId'],
                                 message_data['historyId'])
        return GMailMessage(message_data, self)
예제 #3
0
def get_thread_constructor_args(fn):
    with open(os.path.join(parent_path, fn), 'r') as f:
        d = json.load(f)
    messages = []
    for fields in d['messages']:
        messages.append(GMailMessage(fields, Mock()))
    return d['id'], messages
예제 #4
0
    def test_redirect(self):
    # We will see in tylers inbox that a tenant has submitted a rental application
    # We will look in the apply inbox for the thread of that tenant
    # We will create a draft in that thread under apply
        from orgs.example_org.ExampleOrg import header, signature 
        import orgs.example_org.ExampleOrg

        draft_text = 'I just processed the application'
        orgs.example_org.ExampleOrg.example_rule_construction_data = [header, \
['redirect', 'tyler', 'apply', '', 'Rental Application .*', '', '', 'redirect','"{}"'.format(draft_text), 'inbox.query(get_new_application_email(thread))', 'thread.default_reply()', '5', '', '']]

        tyler_service = Mock()
        tyler_threads = [Thread(*get_thread_constructor_args('integration_test_inputs/rental_application.txt'), tyler_service)]
        tyler_service.query = MagicMock(return_value=tyler_threads)
        tyler_service.get_user = MagicMock(return_value='tyler')
        tyler_service.get_email = MagicMock(return_value='*****@*****.**')
        tyler_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])
        tyler_service.get_all_history_ids = MagicMock(return_value={})

        apply_service = Mock()
        apply_threads = [Thread(*get_thread_constructor_args('integration_test_inputs/conversation_between_apply_inbox_and_tenant.txt'), apply_service)]
        apply_service.query = MagicMock(return_value=apply_threads)
        # We need to have this mocked so that the apply inbox can be searched
        apply_service.get_all_threads = MagicMock(return_value=apply_threads)
        apply_service.get_user = MagicMock(return_value='apply')
        apply_service.get_email = MagicMock(return_value='*****@*****.**')
        apply_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])

        draft_id = '1234'
        draft_msg_id = '2345'
        apply_service.get_drafts = MagicMock(return_value=[{'id' : draft_id, 'message' : {'id' : draft_msg_id}}])
        apply_service.append_or_create_draft = MagicMock(return_value=GMailMessage({'id' : draft_msg_id, 'snippet' : draft_text, 'labelIds' : ['DRAFT'], 'payload' : {'body' : { 'data' : encode_for_payload(draft_text)}, 'headers' : [{'name' : 'to', 'value' : 'Tyler Galdes <*****@*****.**>'}]}}, {}))
        apply_service.set_label = MagicMock(return_value={'labelIds' : ['test label id for "automation" label']})
        apply_service.get_all_history_ids = MagicMock(return_value={})
        config = {}
        config['org'] = {}
        config['org']['name'] = 'example_org'
        config['org']['imports'] = ['from orgs.example_org.ExampleOrg import signature', 'from orgs.example_org.ExampleOrg import get_new_application_email']
        config['org_init_import'] = 'from orgs.example_org.ExampleOrg import org_init'
        logger = Logger('TestIntegration')
        m = Main([tyler_service, apply_service], logger, config)

        m.setup()
        m.run_one()
        mime_multipart, thread_id, called_draft_id = apply_service.append_or_create_draft.call_args[0]
        self.assertIsNone(called_draft_id)
        self.assertEqual('*****@*****.**', mime_multipart['from'])
        self.assertEqual('*****@*****.**', mime_multipart['to'])
        self.assertEqual('New submission for USC', mime_multipart['subject'])
        self.assertEqual('<CACUCK-CJ6Aq-+i=h3bo5745o59FsfXQbfTX5xKeLFS7jM-JpGw@mail.gmail.com>', mime_multipart['In-Reply-To'])
        self.assertEqual('<CACUCK-CJ6Aq-+i=h3bo5745o59FsfXQbfTX5xKeLFS7jM-JpGw@mail.gmail.com>', mime_multipart['References'])
        self.assertEqual(draft_text, mime_multipart.__dict__['_payload'][0].__dict__['_payload'])

        self.assertTrue(apply_threads[0].has_draft())
        self.assertTrue(draft_text in apply_threads[0].existing_draft_text())
예제 #5
0
    def test_lookup_info(self):
    # Use the lookup_info class to populate the draft and the draft destinations
        from orgs.example_org.ExampleOrg import header, signature 
        import orgs.example_org.ExampleOrg

        orgs.example_org.ExampleOrg.example_rule_construction_data = [header, \
['lookup_info_test', 'apply', '', 'Schools/(.*)', '', 'submitted my application', 'not thread.is_last_message_from_us()', 'draft','lookup_info("parking", match(0))', '', 'lookup_info("executed_leases", match(0))', '5', '', '']]
        
        school = 'USC'
        dest_email = '[email protected],[email protected]'
        parking_info = 'information about parking'

        apply_service = Mock()
        apply_threads = [Thread(*get_thread_constructor_args('integration_test_inputs/conversation_between_apply_inbox_and_tenant.txt'), apply_service)]
        apply_service.query = MagicMock(return_value=apply_threads)
        apply_service.get_user = MagicMock(return_value='apply')
        apply_service.get_email = MagicMock(return_value='*****@*****.**')
        apply_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])
        apply_service.get_label_name = MagicMock(return_value='Schools/USC')

        draft_id = '1234'
        draft_msg_id = '2345'
        apply_service.get_drafts = MagicMock(return_value=[{'id' : draft_id, 'message' : {'id' : draft_msg_id}}])
        apply_service.append_or_create_draft = MagicMock(return_value=GMailMessage({'id' : draft_msg_id, 'snippet' : parking_info, 'labelIds' : ['DRAFT'], 'payload' : {'body' : { 'data' : encode_for_payload(parking_info)}, 'headers' : [{'name' : 'to', 'value' : '<{}>,<{}>'.format(*dest_email.split(','))}]}}, {}))
        apply_service.set_label = MagicMock(return_value={'labelIds' : ['test label id for "automation" label']})
        apply_service.get_all_history_ids = MagicMock(return_value={})
        config = {}
        config['org'] = {}
        config['org']['name'] = 'example_org'
        config['org']['imports'] = ['from orgs.example_org.ExampleOrg import signature', 'from orgs.example_org.ExampleOrg import lookup_info']
        logger = Logger('TestIntegration')
        config['lookup_info'] = [['parking', school, parking_info], ['', 'UCLA', 'more info'], ['executed_leases', school, dest_email], ['', 'UCLA', '*****@*****.**']]
        config['org_init_import'] = 'from orgs.example_org.ExampleOrg import org_init'
        m = Main([apply_service], logger, config)

        m.setup()
        m.run_one()
        mime_multipart, thread_id, called_draft_id = apply_service.append_or_create_draft.call_args[0]
        self.assertIsNone(called_draft_id)
        self.assertEqual('*****@*****.**', mime_multipart['from'])
        for email in dest_email.split(','):
            self.assertTrue(email in mime_multipart['to'])
        self.assertEqual('New submission for USC', mime_multipart['subject'])
        self.assertEqual('<CACUCK-CJ6Aq-+i=h3bo5745o59FsfXQbfTX5xKeLFS7jM-JpGw@mail.gmail.com>', mime_multipart['In-Reply-To'])
        self.assertEqual('<CACUCK-CJ6Aq-+i=h3bo5745o59FsfXQbfTX5xKeLFS7jM-JpGw@mail.gmail.com>', mime_multipart['References'])
        self.assertEqual(parking_info, mime_multipart.__dict__['_payload'][0].__dict__['_payload'])


        self.assertTrue('Schools/{}'.format(school) in apply_threads[0].labels())
        self.assertTrue(apply_threads[0].has_draft())
        self.assertTrue(parking_info in apply_threads[0].existing_draft_text())
예제 #6
0
 def send_draft(self, draft_id):
     try:
         message_data = self.service.users().drafts().send(userId='me',
                                                           body={
                                                               'id':
                                                               draft_id
                                                           }).execute()
         # get the full message
         full_message_data = self.service.users().messages().get(
             userId='me', id=message_data['id']).execute()
         message = GMailMessage(full_message_data, self)
         if message:  # remove this draft id
             # TODO: better design to hold drafts in a map with draft id as the key
             for i, d in enumerate(self.drafts):
                 if d['id'] == draft_id:
                     del self.drafts[i]
                     break
         self.__update_history_id(full_message_data['threadId'],
                                  full_message_data['historyId'])
         return message
     except:
         return None
예제 #7
0
    def test_catch_exception_on_individual_thread_and_blacklist(self):
    # two rules- one to label everything, one to add a draft to everything
    # two threads. the first will throw when we try to add a label to it
    # we expect to catch that exception and not process that thread any more
    # we'll end up with no drafts on the bad thread, and add a label and a draft to the good thread

        test_draft_text = 'test draft'
        from orgs.example_org.ExampleOrg import header
        example_rule_construction_data = [header, \
        # label rule, will always match .* and run
            ['Label by school', 'tyler', '', '', '', '', '', 'draft', test_draft_text, '', '', '1', 'ifelse', ''], \
        # draft rule, will always match empty matcher
            ['add draft', 'tyler', '', '', '', '', '', 'draft', test_draft_text, '', 'thread.default_reply()', '2', '', '', '']]

        good_service = Mock()
        bad_service = Mock()
        bad_thread = Thread(*get_thread_constructor_args('integration_test_inputs/one_email_thread.txt'), bad_service)
        good_thread = Thread(*get_thread_constructor_args('integration_test_inputs/rental_application.txt'), good_service)
        all_threads = [bad_thread, good_thread]


        # set up good service
        good_service.query = MagicMock(return_value=all_threads)
        good_service.get_label_name = MagicMock(return_value='Schools')
        good_service.set_label = MagicMock(return_value={'labelIds' : ['test label id']})
        good_service.get_all_history_ids = MagicMock(return_value={})
        good_service.get_user = MagicMock(return_value='tyler')
        good_service.get_email = MagicMock(return_value='*****@*****.**')
        good_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])

        draft_id = '1234'
        draft_msg_id = '2345'
        good_service.get_drafts = MagicMock(return_value=[{'id' : draft_id, 'message' : {'id' : draft_msg_id}}])
        dest_email = '[email protected],[email protected]'
        good_service.append_or_create_draft = MagicMock(return_value=GMailMessage({'id' : draft_msg_id, 'snippet' : test_draft_text, 'labelIds' : ['DRAFT'], 'payload' : {'body' : { 'data' : encode_for_payload(test_draft_text)}, 'headers' : [{'name' : 'to', 'value' : '<{}>,<{}>'.format(*dest_email.split(','))}]}}, {}))

        # set up bad service, will throw on create_or_append_draft
        bad_service.query = MagicMock(return_value=all_threads)
        bad_service.get_label_name = MagicMock(return_value='Schools')
        bad_service.set_label = MagicMock(return_value={'labelIds' : ['test label id']})
        bad_service.get_all_history_ids = MagicMock(return_value={})
        bad_service.get_user = MagicMock(return_value='tyler')
        bad_service.get_email = MagicMock(return_value='*****@*****.**')
        bad_service.get_domains = MagicMock(return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])

        draft_id = '1234'
        draft_msg_id = '2345'
        bad_service.get_drafts = MagicMock(return_value=[{'id' : draft_id, 'message' : {'id' : draft_msg_id}}])
        bad_service.append_or_create_draft = MagicMock(side_effect=Exception)

        config = {}
        config['org'] = {}
        config['org']['name'] = 'example_org'
        config['org']['imports'] = ['from orgs.example_org.ExampleOrg import signature']
        config['org_init_import'] = 'from orgs.example_org.ExampleOrg import org_init'
        logger = Logger('TestIntegration')
        m = Main([good_service, bad_service], logger, config)

        m.setup()
        # if we don't catch the exception here we'll fail
        m.run_one()

        self.assertEqual(2, good_service.append_or_create_draft.call_count)
        self.assertEqual(2, good_service.set_label.call_count) # will set the label as 'automation' twice
        self.assertEqual(1, bad_service.set_label.call_count) # got hit once while setting the label for automation/errors
        self.assertTrue(bad_thread.id() in m.inboxes['tyler'].blacklisted_thread_ids)
        self.assertEqual(1, len(m.inboxes['tyler'].blacklisted_thread_ids))
예제 #8
0
    def test_new_submission_handler(self):

        rule_construction_data = [header, \
['test new submission handler', 'apply', '', 'automation/contact_form', '', '', 'len(thread) == 1', 'draft','run_new_submission_handler(thread)', '', 'thread.default_reply()', '1', '', '', '']]

        apply_service = Mock()
        apply_threads = [
            Thread(
                *get_thread_constructor_args(
                    '../orgs/cfld/test/integration_test_inputs/new_submission_only.txt'
                ), apply_service)
        ]
        apply_service.query = MagicMock(return_value=apply_threads)
        apply_service.get_user = MagicMock(return_value='apply')
        apply_service.get_email = MagicMock(
            return_value='*****@*****.**')
        apply_service.get_domains = MagicMock(
            return_value=['cleanfloorslockingdoors.com', 'cf-ld.com'])
        apply_service.get_label_name = MagicMock(
            return_value='automation/contact_form')

        draft_id = '1234'
        draft_msg_id = '2345'
        apply_service.get_drafts = MagicMock(return_value=[{
            'id': draft_id,
            'message': {
                'id': draft_msg_id
            }
        }])
        # Return an empty message instead of creating a brittle assert on how the new
        # submission handler will put together a response
        apply_service.append_or_create_draft = MagicMock(
            return_value=GMailMessage(
                {
                    'id': draft_msg_id,
                    'snippet': '',
                    'labelIds': ['DRAFT'],
                    'payload': {
                        'body': {
                            'data': ''
                        },
                        'headers': [{
                            'name': 'to',
                            'value': '<*****@*****.**>'
                        }]
                    }
                }, {}))
        apply_service.set_label = MagicMock(return_value={
            'labelIds': ['test label id for "automation" label']
        })
        apply_service.get_all_history_ids = MagicMock(return_value={})
        config = {}
        config['org'] = {}
        config['org']['name'] = 'cfld'
        config['org']['imports'] = ["from orgs.cfld.CfldOrg import run_new_submission_handler", \
                     "from orgs.cfld.util import get_new_application_email", \
                     "from orgs.cfld.util import signature", \
                     "from orgs.cfld.CfldOrg import lookup_info", \
                     "from orgs.cfld.CfldOrg import short_name_from_address", \
                     "from orgs.cfld.util import short_name_from_thread"]
        logger = Logger('TestIntegration')
        config['org_init_import'] = 'from orgs.cfld.CfldOrg import org_init'
        m = Main([apply_service], logger, config)
        # use our "bastard initialization"
        direct_initialize_org(rule_construction_data, raw_availability,
                              raw_availability_blurbs, [])

        m.setup()
        m.run_one()
        mime_multipart, thread_id, called_draft_id = apply_service.append_or_create_draft.call_args[
            0]
        self.assertIsNone(called_draft_id)
        self.assertEqual('*****@*****.**',
                         mime_multipart['from'])
        self.assertTrue('*****@*****.**' in mime_multipart['to'])
        self.assertEqual('New submission for UCLA', mime_multipart['subject'])
        self.assertEqual(
            '<*****@*****.**>',
            mime_multipart['In-Reply-To'])
        self.assertEqual(
            '<*****@*****.**>',
            mime_multipart['References'])
        self.assertTrue(open_at_desired_move_in in mime_multipart.
                        __dict__['_payload'][0].__dict__['_payload'])
        self.assertTrue(nothing_open in mime_multipart.__dict__['_payload']
                        [0].__dict__['_payload'])
예제 #9
0
 def __create_thread_from_raw(self, raw_thread):
     messages = []
     for message in raw_thread['messages']:
         messages.append(GMailMessage(message, self))
     return Thread(raw_thread['id'], messages, self)