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)
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)
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
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())
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())
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
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))
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'])
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)