def process_ingestion_emails(): """ Gets all new mail documents in the bucket and process each message. """ processor = CalendarInteractionEmailProcessor() for message in get_mail_docs_in_bucket(): source = message['source'] try: documents.delete_document(bucket_id=BUCKET_ID, document_key=message['source']) except Exception as e: logger.exception('Error deleting message: "%s", error: "%s"', source, e) continue try: email = mailparser.parse_from_bytes(message['content']) processed, reason = processor.process_email(message=email) if not processed: logger.error('Error parsing message: "%s", error: "%s"', source, reason) else: logger.info(reason) except Exception as e: logger.exception('Error processing message: "%s", error: "%s"', source, e) logger.info( 'Successfully processed message "%s" and deleted document from bucket "%s"', source, BUCKET_ID, )
def test_process_email_validation( self, interaction_data_overrides, expected_message, base_interaction_data_fixture, calendar_data_fixture, mock_notify_adviser_by_email, interaction_email_notification_feature_flag, mock_message, monkeypatch, ): """ Test that process_email returns expected validation error messages when called with invalid data. """ interaction_data = {**base_interaction_data_fixture, **interaction_data_overrides} self._get_email_parser_mock(interaction_data, monkeypatch) processor = CalendarInteractionEmailProcessor() result, message = processor.process_email(mock_message) assert result is False assert message == expected_message mock_notify_adviser_by_email.assert_called_once_with( Advisor.objects.filter(email=base_interaction_data_fixture['sender_email']).first(), Template.meeting_ingest_failure.value, context={ 'errors': [expected_message], 'recipients': ', '.join(base_interaction_data_fixture['contact_emails']), 'support_team_email': settings.DATAHUB_SUPPORT_EMAIL_ADDRESS, }, )
def test_process_email_meeting_exists( self, base_interaction_data_fixture, calendar_data_fixture, interaction_email_notification_feature_flag, mock_message, monkeypatch, ): """ Test that process_email does not save another interaction when the meeting already exists as an interaction. """ interaction_data = {**base_interaction_data_fixture} self._get_email_parser_mock(interaction_data, monkeypatch) processor = CalendarInteractionEmailProcessor() # Create the calendar interaction initially initial_result, initial_message = processor.process_email(mock_message) interaction_id = initial_message.split()[-1].strip('#') assert initial_result is True # Simulate processing the email again duplicate_result, duplicate_message = processor.process_email(mock_message) assert duplicate_result is False assert duplicate_message == 'Meeting already exists as an interaction' all_interactions_by_sender = Interaction.objects.filter( dit_participants__adviser=Advisor.objects.get(email=interaction_data['sender_email']), ) assert all_interactions_by_sender.count() == 1 assert all_interactions_by_sender[0].id == UUID(interaction_id)
def test_process_email_parser_validation_error( self, base_interaction_data_fixture, calendar_data_fixture, mock_notify_adviser_by_email, interaction_email_notification_feature_flag, mock_message, monkeypatch, caplog, invalid_invite_exception_class, expected_to_notify, ): """ Test that process_email returns an expected message when the parser raises a ValidationError. """ caplog.set_level(logging.WARNING) interaction_data = {**base_interaction_data_fixture} mock_parser = self._get_email_parser_mock(interaction_data, monkeypatch) exception = invalid_invite_exception_class('There was a problem with the meeting format') mock_parser.side_effect = exception expected_exception_string = repr(exception) processor = CalendarInteractionEmailProcessor() result, message = processor.process_email(mock_message) assert result is False assert message == expected_exception_string expected_log = ( 'datahub.interaction.email_processors.processors', 30, 'Ingested email with ID "abc123" (received 2019-08-01T00:00:01) ' f'was not valid: {expected_exception_string}', ) assert expected_log in caplog.record_tuples if expected_to_notify: expected_error_message = ( EXCEPTION_NOTIFY_MESSAGES[invalid_invite_exception_class] ) mock_notify_adviser_by_email.assert_called_once_with( Advisor.objects.filter( email=base_interaction_data_fixture['sender_email'], ).first(), Template.meeting_ingest_failure.value, context={ 'errors': [expected_error_message], 'recipients': ', '.join(base_interaction_data_fixture['contact_emails']), 'support_team_email': settings.DATAHUB_SUPPORT_EMAIL_ADDRESS, }, ) else: mock_notify_adviser_by_email.assert_not_called()
def test_process_email_successful( self, interaction_data_overrides, expected_subject, calendar_data_fixture, base_interaction_data_fixture, mock_notify_adviser_by_email, interaction_email_notification_feature_flag, mock_message, monkeypatch, ): """ Test that process_email saves a draft interaction when the calendar parser yields good data. """ interaction_data = { **base_interaction_data_fixture, **interaction_data_overrides, } email_parser_mock = self._get_email_parser_mock(interaction_data, monkeypatch) # Process the message and save a draft interaction processor = CalendarInteractionEmailProcessor() result, message = processor.process_email(mock_message) assert result is True interaction = Interaction.objects.get(source__meeting__id='12345') assert message == f'Successfully created interaction #{interaction.id}' # Verify dit_participants holds all of the advisers for the interaction expected_adviser_emails = { interaction_data['sender_email'], *interaction_data['secondary_adviser_emails'], } interaction_adviser_emails = { participant.adviser.email for participant in interaction.dit_participants.all() } assert interaction_adviser_emails == expected_adviser_emails # Verify contacts holds all of the expected contacts for the interaction interaction_contacts = interaction.contacts.all() email_contacts = email_parser_mock.return_value['contacts'] for contact in email_contacts: if contact.company.name == interaction_data['top_company_name']: assert contact in interaction_contacts assert interaction.company.name == interaction_data['top_company_name'] assert interaction.date == interaction_data['date'] assert interaction.source == { 'meeting': {'id': interaction_data['meeting_details']['uid']}, } assert interaction.subject == expected_subject assert interaction.status == Interaction.Status.DRAFT sender_participant = interaction.dit_participants.get( adviser__email__iexact=interaction_data['sender_email'], ) mock_notify_adviser_by_email.assert_called_once_with( sender_participant.adviser, Template.meeting_ingest_success.value, context={ 'interaction_url': interaction.get_absolute_url(), 'recipients': '[email protected], [email protected]', 'support_team_email': settings.DATAHUB_SUPPORT_EMAIL_ADDRESS, }, )