import email import uuid from helpdesk.models import Queue, CustomField, FollowUp, Ticket, TicketCC from django.test import TestCase from django.core import mail from django.core.exceptions import ObjectDoesNotExist from django.forms import ValidationError from django.test.client import Client from django.urls import reverse from helpdesk.email import object_from_message, create_ticket_cc from urllib.parse import urlparse import logging logger = logging.getLogger('helpdesk') class TicketBasicsTestCase(TestCase): fixtures = ['emailtemplate.json'] def setUp(self): self.queue_public = Queue.objects.create( title='Queue 1', slug='q1', allow_public_submission=True, new_ticket_cc='new.public@example.com', updated_ticket_cc='update.public@example.com') self.queue_private = Queue.objects.create( title='Queue 2', slug='q2', allow_public_submission=False, new_ticket_cc='new.private@example.com', updated_ticket_cc='update.private@example.com') self.ticket_data = { 'title': 'Test Ticket', 'description': 'Some Test Ticket', } self.client = Client() def test_create_ticket_instance_from_payload(self): """ Ensure that a instance is created whenever an email is sent to a public queue. """ email_count = len(mail.outbox) ticket_data = dict(queue=self.queue_public, **self.ticket_data) ticket = Ticket.objects.create(**ticket_data) self.assertEqual(ticket.ticket_for_url, "q1-%s" % ticket.id) self.assertEqual(email_count, len(mail.outbox)) def test_create_ticket_public(self): email_count = len(mail.outbox) response = self.client.get(reverse('helpdesk:home')) self.assertEqual(response.status_code, 200) post_data = { 'title': 'Test ticket title', 'queue': self.queue_public.id, 'submitter_email': 'ticket1.submitter@example.com', 'body': 'Test ticket body', 'priority': 3, } response = self.client.post(reverse('helpdesk:home'), post_data, follow=True) last_redirect = response.redirect_chain[-1] last_redirect_url = last_redirect[0] # last_redirect_status = last_redirect[1] # Ensure we landed on the "View" page. # Django 1.9 compatible way of testing this # https://docs.djangoproject.com/en/1.9/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris urlparts = urlparse(last_redirect_url) self.assertEqual(urlparts.path, reverse('helpdesk:public_view')) # Ensure submitter, new-queue + update-queue were all emailed. self.assertEqual(email_count + 3, len(mail.outbox)) def test_create_ticket_private(self): email_count = len(mail.outbox) post_data = { 'title': 'Private ticket test', 'queue': self.queue_private.id, 'submitter_email': 'ticket2.submitter@example.com', 'body': 'Test ticket body', 'priority': 3, } response = self.client.post(reverse('helpdesk:home'), post_data) self.assertEqual(response.status_code, 200) self.assertEqual(email_count, len(mail.outbox)) self.assertContains(response, 'Select a valid choice.') def test_create_ticket_customfields(self): email_count = len(mail.outbox) queue_custom = Queue.objects.create( title='Queue 3', slug='q3', allow_public_submission=True, updated_ticket_cc='update.custom@example.com') custom_field_1 = CustomField.objects.create( name='textfield', label='Text Field', data_type='varchar', max_length=100, ordering=10, required=False, staff_only=False) post_data = { 'queue': queue_custom.id, 'title': 'Ticket with custom text field', 'submitter_email': 'ticket3.submitter@example.com', 'body': 'Test ticket body', 'priority': 3, 'custom_textfield': 'This is my custom text.', } response = self.client.post(reverse('helpdesk:home'), post_data, follow=True) custom_field_1.delete() last_redirect = response.redirect_chain[-1] last_redirect_url = last_redirect[0] # last_redirect_status = last_redirect[1] # Ensure we landed on the "View" page. # Django 1.9 compatible way of testing this # https://docs.djangoproject.com/en/1.9/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris urlparts = urlparse(last_redirect_url) self.assertEqual(urlparts.path, reverse('helpdesk:public_view')) # Ensure only two e-mails were sent - submitter & updated. self.assertEqual(email_count + 2, len(mail.outbox)) class EmailInteractionsTestCase(TestCase): fixtures = ['emailtemplate.json'] def setUp(self): self.queue_public = Queue.objects.create( title='Mail Queue 1', slug='mq1', email_address='queue-1@example.com', allow_public_submission=True, new_ticket_cc='new.public.with.notifications@example.com', updated_ticket_cc='update.public.with.notifications@example.com', enable_notifications_on_email_events=True, ) self.queue_public_with_notifications_disabled = Queue.objects.create( title='Mail Queue 2', slug='mq2', email_address='queue-2@example.com', allow_public_submission=True, new_ticket_cc='new.public.without.notifications@example.com', updated_ticket_cc='update.public.without.notifications@example.com', enable_notifications_on_email_events=False, ) self.ticket_data = { 'title': 'Test Ticket', 'description': 'Some Test Ticket', } def test_create_ticket_from_email_with_message_id(self): """ Ensure that a instance is created whenever an email is sent to a public queue. Also, make sure that the RFC 2822 field "message-id" is stored on the field. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify the sender (+1) # and the new and update queues (+2) self.assertEqual(email_count + 1 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) def test_create_ticket_from_email_without_message_id(self): """ Ensure that a instance is created whenever an email is sent to a public queue. Also, make sure that the RFC 2822 field "message-id" is stored on the field. """ msg = email.message.Message() submitter_email = 'foo@bar.py' msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) ticket = Ticket.objects.get(title=self.ticket_data['title'], queue=self.queue_public, submitter_email=submitter_email) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify the sender (+1) # and the new and update queues (+2) self.assertEqual(email_count + 1 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) def test_create_ticket_from_email_with_carbon_copy(self): """ Ensure that an instance of is created for every valid element of the "rfc_2822_cc" field when creating a instance. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) self.assertEqual(email_count + 1 + 2 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) # Ensure that exists ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_ticket_from_email_to_multiple_emails(self): """ Ensure that an instance of is created for every valid element of the "rfc_2822_cc" field when creating a instance. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' to_list = [self.queue_public.email_address] cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', ','.join(to_list + cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) self.assertEqual(email_count + 1 + 2 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) # Ensure that the queue's email was not subscribed to the event notifications. self.assertRaises(TicketCC.DoesNotExist, TicketCC.objects.get, ticket=ticket, email=to_list[0]) for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) # Ensure that exists ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_ticket_from_email_with_invalid_carbon_copy(self): """ Ensure that no instance is created if an invalid element of the "rfc_2822_cc" field is provided when creating a instance. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['null@example', 'invalid@foobar'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the submitter (+1) # contacts on the cc_list (+2), # the new and update queues (+2) self.assertEqual(email_count + 1 + 2 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) # Ensure that exists. Even if it's an invalid email. ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_followup_from_email_with_valid_message_id_with_no_initial_cc_list(self): """ Ensure that if a message is received with an valid In-Reply-To ID, the expected instances are created even if the there were no s so far. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) # As we have created an Ticket from an email, we notify the sender # and contacts on the cc_list (+1 as it's treated as a list), # the new and update queues (+2) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) # As we have created an Ticket from an email, we notify the sender (+1) # and the new and update queues (+2) expected_email_count = 1 + 2 self.assertEqual(expected_email_count, len(mail.outbox)) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', message_id) reply.__setitem__('Subject', self.ticket_data['title']) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public.email_address) reply.__setitem__('Cc', ','.join(cc_list)) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) object_from_message(str(reply), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # Ensure that is created for cc_email in cc_list: # Even after 2 messages with the same cc_list, MUST return only # one object ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # As an update was made, we increase the expected_email_count with: # submitter: +1 # cc_list: +2 # public_update_queue: +1 expected_email_count += 1 + 2 + 1 self.assertEqual(expected_email_count, len(mail.outbox)) # As we have created a FollowUp from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) # Ensure that the submitter is notified # self.assertIn(submitter_email, mail.outbox[expected_email_count - 3].to) # Ensure that contacts on cc_list will be notified on the same email (index 0) # for cc_email in cc_list: # self.assertIn(cc_email, mail.outbox[expected_email_count - 1].to) def test_create_followup_from_email_with_valid_message_id_with_original_cc_list_included(self): """ Ensure that if a message is received with an valid In-Reply-To ID, the expected instances are created but if there's any overlap with the previous Cc list, no duplicates are created. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) # Ensure that is created for cc_email in cc_list: ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) self.assertTrue(ticket_cc.can_view, True) # As we have created a Ticket from an email, we notify the sender # and contacts on the cc_list (+1 as it's treated as a list), # the new and update queues (+2) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) # As we have created an Ticket from an email, we notify the sender (+1) # and the new and update queues (+2) expected_email_count = 1 + 2 self.assertEqual(expected_email_count, len(mail.outbox)) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', message_id) reply.__setitem__('Subject', self.ticket_data['title']) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public.email_address) reply.__setitem__('Cc', ','.join(cc_list)) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) object_from_message(str(reply), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As an update was made, we increase the expected_email_count with: # public_update_queue: +1 expected_email_count += 1 self.assertEqual(expected_email_count, len(mail.outbox)) # As we have created a FollowUp from an email, we notify the sender # and contacts on the cc_list (+1 as it's treated as a list), # the new and update queues (+2) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[expected_email_count - 1].to) # Ensure that contacts on cc_list will be notified on the same email (index 0) for cc_email in cc_list: self.assertIn(cc_email, mail.outbox[expected_email_count - 1].to) # Even after 2 messages with the same cc_list, # MUST return only one object ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_followup_from_email_with_invalid_message_id(self): """ Ensure that if a message is received with an invalid In-Reply-To ID and we can infer the original Ticket ID by the message's subject, the expected instances are created. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) # Ensure that is created for cc_email in cc_list: ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) self.assertTrue(ticket_cc.can_view, True) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) expected_email_count = 1 + 2 + 2 self.assertEqual(expected_email_count, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) # Ensure that is created for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] invalid_message_id = 'INVALID' reply_subject = 'Re: ' + self.ticket_data['title'] reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', invalid_message_id) reply.__setitem__('Subject', reply_subject) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public.email_address) reply.__setitem__('Cc', ','.join(cc_list)) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(reply), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # Ensure that is created for cc_email in cc_list: # Even after 2 messages with the same cc_list, MUST return only # one object ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) self.assertEqual(email_count + 1 + 2 + 2, len(mail.outbox)) def test_create_ticket_from_email_to_a_notification_enabled_queue(self): """ Ensure that when an email is sent to a Queue with notifications_enabled turned ON, and a is created, all contacts in the TicketCC list are notified. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) self.assertEqual(email_count + 1 + 2 + 2, len(mail.outbox)) # Ensure that the submitter is notified self.assertIn(submitter_email, mail.outbox[0].to) # Ensure that exist for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_ticket_from_email_to_a_notification_disabled_queue(self): """ Ensure that when an email is sent to a Queue with notifications_enabled turned OFF, only the new_ticket_cc and updated_ticket_cc contacts (if they are set) are notified. No contact from the TicketCC list should be notified. """ msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public_with_notifications_disabled.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public_with_notifications_disabled, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq2-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # the new and update queues (+2), # and that's it because we've disabled queue notifications self.assertEqual(email_count + 1 + 2, len(mail.outbox)) # Ensure that is created even if the Queue notifications are disabled # so when staff members interact with the , they get notified for cc_email in cc_list: # Ensure that contacts on the cc_list are not notified self.assertNotIn(cc_email, mail.outbox[0].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_followup_from_email_to_a_notification_enabled_queue(self): """ Ensure that when an email is sent to a Queue with notifications_enabled turned ON, and a is created, all contacts n the TicketCC list are notified. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # contacts on the cc_list (+2), # the new and update queues (+2) expected_email_count = email_count + 1 + 2 + 2 self.assertEqual(expected_email_count, len(mail.outbox)) # Ensure that is created for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[0].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'bravo@example.net' reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', message_id) reply.__setitem__('Subject', self.ticket_data['title']) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public.email_address) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) object_from_message(str(reply), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # As an update was made, we increase the expected_email_count with: # submitter: +1 # a new email to all TicketCC subscribers : +2 # public_update_queue: +1 expected_email_count += 1 + 2 + 1 self.assertEqual(expected_email_count, len(mail.outbox)) # Ensure that exist for cc_email in cc_list: # Ensure that contacts on cc_list will be notified on the same email (index 0) # self.assertIn(cc_email, mail.outbox[expected_email_count - 1].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) def test_create_followup_from_email_to_a_notification_disabled_queue(self): """ Ensure that when an email is sent to a Queue with notifications_enabled turned OFF, and a is created, TicketCC is NOT notified. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' cc_list = ['bravo@example.net', 'charlie@foobar.com'] msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public_with_notifications_disabled.email_address) msg.__setitem__('Cc', ','.join(cc_list)) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public_with_notifications_disabled, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq2-%s" % ticket.id) # As we have created an Ticket from an email, we notify: # the sender (+1), # the new and update queues (+2) expected_email_count = email_count + 1 + 2 self.assertEqual(expected_email_count, len(mail.outbox)) # Ensure that is created for cc_email in cc_list: # Ensure that contacts on cc_list will not be notified self.assertNotIn(cc_email, mail.outbox[0].to) ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'bravo@example.net' reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', message_id) reply.__setitem__('Subject', self.ticket_data['title']) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public_with_notifications_disabled.email_address) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) object_from_message(str(reply), self.queue_public_with_notifications_disabled, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq2-%s" % ticket.id) # As an update was made, we increase the expected_email_count with: # public_update_queue: +1 expected_email_count += 1 self.assertEqual(expected_email_count, len(mail.outbox)) def test_create_followup_from_email_with_valid_message_id_with_original_cc_list_included(self): """ Ensure that if a message is received with an valid In-Reply-To ID, the expected instances are created even if the there were no s so far. """ # Ticket and TicketCCs creation # msg = email.message.Message() message_id = uuid.uuid4().hex submitter_email = 'foo@bar.py' msg.__setitem__('Message-ID', message_id) msg.__setitem__('Subject', self.ticket_data['title']) msg.__setitem__('From', submitter_email) msg.__setitem__('To', self.queue_public.email_address) msg.__setitem__('Content-Type', 'text/plain;') msg.set_payload(self.ticket_data['description']) email_count = len(mail.outbox) object_from_message(str(msg), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) # end of the Ticket and TicketCCs creation # # Reply message reply = email.message.Message() reply_message_id = uuid.uuid4().hex submitter_email = 'bravo@example.net' cc_list = ['foo@bar.py', 'charlie@foobar.com'] reply.__setitem__('Message-ID', reply_message_id) reply.__setitem__('In-Reply-To', message_id) reply.__setitem__('Subject', self.ticket_data['title']) reply.__setitem__('From', submitter_email) reply.__setitem__('To', self.queue_public.email_address) reply.__setitem__('Cc', ','.join(cc_list)) reply.__setitem__('Content-Type', 'text/plain;') reply.set_payload(self.ticket_data['description']) object_from_message(str(reply), self.queue_public, logger=logger) followup = FollowUp.objects.get(message_id=message_id) ticket = Ticket.objects.get(id=followup.ticket.id) self.assertEqual(ticket.ticket_for_url, "mq1-%s" % ticket.id) # Ensure that is created for cc_email in cc_list: # Even after 2 messages with the same cc_list, MUST return only # one object ticket_cc = TicketCC.objects.get(ticket=ticket, email=cc_email) self.assertTrue(ticket_cc.ticket, ticket) self.assertTrue(ticket_cc.email, cc_email) # As we have created an Ticket from an email, we notify the sender (+1) # and the new and update queues (+2) expected_email_count = 1 + 2 # As an update was made, we increase the expected_email_count with: # submitter: +1 # cc_list: +2 # public_update_queue: +1 expected_email_count += 1 + 2 + 1 self.assertEqual(expected_email_count, len(mail.outbox))