def test_incident_started(self): self.org.add_user(self.editor, OrgRole.ADMINISTRATOR) # upgrade editor to administrator Incident.flagged(self.org) self.assert_notifications( expected_json={ "type": "incident:started", "created_on": matchers.ISODate(), "target_url": "/incident/", "is_seen": False, "incident": { "type": "org:flagged", "started_on": matchers.ISODate(), "ended_on": None, }, }, expected_users={self.editor, self.admin}, email=False, ) # if a user visits the incident page, all incident notifications are now read self.login(self.editor) self.client.get("/incident/") self.assertTrue(self.editor.notifications.get().is_seen) self.assertFalse(self.admin.notifications.get().is_seen)
def test_from_flow_run(self): contact = self.create_contact("Jim", phone="0979111111") flow = self.get_flow("color_v13") nodes = flow.get_definition()["nodes"] (MockSessionWriter(contact, flow).visit(nodes[0]).send_msg( "What is your favorite color?", self.channel).wait().save()) run = contact.runs.get() self.assertEqual( { "type": "flow_entered", "created_on": matchers.ISODate(), "flow": { "uuid": str(flow.uuid), "name": "Colors" }, "logs_url": None, }, Event.from_flow_run(self.org, self.admin, run), ) # customer support get access to logs self.assertEqual( { "type": "flow_entered", "created_on": matchers.ISODate(), "flow": { "uuid": str(flow.uuid), "name": "Colors" }, "logs_url": f"/flowsession/json/{run.session.uuid}/", }, Event.from_flow_run(self.org, self.customer_support, run), )
def test_list(self): list_url = reverse("notifications.notification_list") # simulate an export finishing export = ExportContactsTask.create(self.org, self.editor) Notification.export_finished(export) # not access for anon self.assertLoginRedirect(self.client.get(list_url)) # check for user with no notifications self.login(self.user) response = self.client.get(list_url) self.assertEqual({"results": []}, response.json()) # check for editor who should have an export completed notification self.login(self.editor) response = self.client.get(list_url) self.assertEqual( { "results": [{ "type": "export:finished", "created_on": matchers.ISODate(), "target_url": f"/assets/download/contact_export/{export.id}/", "is_seen": False, "export": { "type": "contact" }, }] }, response.json(), )
def test_queue_interrupt_by_session(self): jim = self.create_contact("Jim", "+12065551212") flow = self.get_flow("favorites") flow_nodes = flow.as_json()["nodes"] color_prompt = flow_nodes[0] color_split = flow_nodes[2] (MockSessionWriter(jim, flow).visit(color_prompt).send_msg( "What is your favorite color?", self.channel).visit(color_split).wait().save()) run = FlowRun.objects.get(contact=jim) session = run.session run.release("U") self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "interrupt_sessions", "org_id": self.org.id, "task": { "session_ids": [session.id] }, "queued_on": matchers.ISODate(), }, )
def test_message_export_finished(self): export = ExportMessagesTask.create(self.org, self.editor, system_label="I") export.perform() Notification.export_finished(export) self.assertFalse( self.editor.notifications.get(message_export=export).is_seen) # we only notify the user that started the export self.assert_notifications( after=export.created_on, expected_json={ "type": "export:finished", "created_on": matchers.ISODate(), "target_url": f"/assets/download/message_export/{export.id}/", "is_seen": False, "export": { "type": "message" }, }, expected_users={self.editor}, email=True, ) send_notification_emails() self.assertEqual(1, len(mail.outbox)) self.assertEqual("[Temba] Your message export is ready", mail.outbox[0].subject) self.assertEqual(["*****@*****.**"], mail.outbox[0].recipients())
def test_import_finished(self): imp = ContactImport.objects.create( org=self.org, mappings={}, num_records=5, created_by=self.editor, modified_by=self.editor ) # mailroom will create these notifications when it's complete Notification._create_all( imp.org, "import:finished", scope=f"contact:{imp.id}", users=[self.editor], contact_import=imp ) self.assertFalse(self.editor.notifications.get(contact_import=imp).is_seen) # we only notify the user that started the import self.assert_notifications( after=imp.created_on, expected_json={ "type": "import:finished", "created_on": matchers.ISODate(), "target_url": f"/contactimport/read/{imp.id}/", "is_seen": False, "import": {"type": "contact", "num_records": 5}, }, expected_users={self.editor}, email=False, ) # if a user visits the import read page, their notification for that import is now read self.login(self.editor) self.client.get(reverse("contacts.contactimport_read", args=[imp.id])) self.assertTrue(self.editor.notifications.get(contact_import=imp).is_seen)
def test_queue_msg_handling(self): with override_settings(TESTING=False): msg = Msg.create_relayer_incoming(self.org, self.channel, "tel:12065551212", "Hello World", timezone.now()) self.assert_org_queued(self.org, "handler") self.assert_contact_queued(msg.contact) self.assert_queued_handler_task( msg.contact, { "type": "msg_event", "org_id": self.org.id, "task": { "org_id": self.org.id, "channel_id": self.channel.id, "contact_id": msg.contact_id, "msg_id": msg.id, "msg_uuid": str(msg.uuid), "msg_external_id": None, "urn": "tel:+12065551212", "urn_id": msg.contact.urns.get().id, "text": "Hello World", "attachments": None, "new_contact": True, }, "queued_on": matchers.ISODate(), }, )
def test_from_ivr_call(self): contact = self.create_contact("Jim", phone="0979111111") call1 = IVRCall.objects.create( org=self.org, contact=contact, status=IVRCall.STATUS_IN_PROGRESS, channel=self.channel, contact_urn=contact.urns.all().first(), error_count=0, ) call2 = IVRCall.objects.create( org=self.org, contact=contact, status=IVRCall.STATUS_ERRORED, error_reason=IVRCall.ERROR_BUSY, channel=self.channel, contact_urn=contact.urns.all().first(), error_count=0, ) self.assertEqual( { "type": "call_started", "status": "I", "status_display": "In Progress", "created_on": matchers.ISODate(), "logs_url": None, }, Event.from_ivr_call(self.org, self.user, call1), ) self.assertEqual( { "type": "call_started", "status": "E", "status_display": "Errored (Busy)", "created_on": matchers.ISODate(), "logs_url": None, }, Event.from_ivr_call(self.org, self.user, call2), )
def test_queue_interrupt_by_channel(self): self.channel.release() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "interrupt_sessions", "org_id": self.org.id, "task": {"channel_ids": [self.channel.id]}, "queued_on": matchers.ISODate(), }, )
def test_queue_mo_miss_event(self, mr_mocks): get_redis_connection("default").flushall() event = ChannelEvent.create_relayer_event(self.channel, "tel:12065551212", ChannelEvent.TYPE_CALL_OUT, timezone.now()) r = get_redis_connection() # noop, this event isn't handled by mailroom self.assertEqual(0, r.zcard(f"handler:active")) self.assertEqual(0, r.zcard(f"handler:{self.org.id}")) self.assertEqual(0, r.llen(f"c:{self.org.id}:{event.contact_id}")) event = ChannelEvent.create_relayer_event( self.channel, "tel:12065551515", ChannelEvent.TYPE_CALL_IN_MISSED, timezone.now()) self.assert_org_queued(self.org, "handler") self.assert_contact_queued(event.contact) self.assert_queued_handler_task( event.contact, { "type": "mo_miss", "org_id": event.contact.org.id, "task": { "channel_id": self.channel.id, "contact_id": event.contact.id, "event_type": "mo_miss", "extra": None, "id": event.id, "new_contact": False, "occurred_on": matchers.ISODate(), "org_id": event.contact.org.id, "urn_id": event.contact.urns.get().id, }, "queued_on": matchers.ISODate(), }, )
def test_queue_broadcast(self): jim = self.create_contact("Jim", phone="+12065551212") bobs = self.create_group( "Bobs", [self.create_contact("Bob", phone="+12065551313")]) ticketer = Ticketer.create(self.org, self.admin, "mailgun", "Support Tickets", {}) ticket = self.create_ticket(ticketer, jim, "Help!") bcast = Broadcast.create( self.org, self.admin, { "eng": "Welcome to mailroom!", "spa": "¡Bienvenidx a mailroom!" }, groups=[bobs], contacts=[jim], urns=["tel:+12065556666"], base_language="eng", ticket=ticket, ) bcast.send_async() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "send_broadcast", "org_id": self.org.id, "task": { "translations": { "eng": { "text": "Welcome to mailroom!" }, "spa": { "text": "\u00a1Bienvenidx a mailroom!" }, }, "template_state": "legacy", "base_language": "eng", "urns": ["tel:+12065556666"], "contact_ids": [jim.id], "group_ids": [bobs.id], "broadcast_id": bcast.id, "org_id": self.org.id, "ticket_id": ticket.id, }, "queued_on": matchers.ISODate(), }, )
def test_queue_contact_import_batch(self): imp = self.create_contact_import("media/test_imports/simple.xlsx") imp.start() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "import_contact_batch", "org_id": self.org.id, "task": {"contact_import_batch_id": imp.batches.get().id}, "queued_on": matchers.ISODate(), }, )
def test_queue_interrupt_by_flow(self): flow = self.get_flow("favorites") flow.archive() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "interrupt_sessions", "org_id": self.org.id, "task": {"flow_ids": [flow.id]}, "queued_on": matchers.ISODate(), }, )
def test_org_flagged(self): self.org.flag() incident = Incident.objects.get() self.assertEqual("org:flagged", incident.incident_type) self.assertEqual({self.admin}, set(n.user for n in incident.notifications.all())) self.assertEqual( {"type": "org:flagged", "started_on": matchers.ISODate(), "ended_on": None}, incident.as_json() ) self.org.unflag() incident = Incident.objects.get() # still only have 1 incident, but now it has ended self.assertEqual("org:flagged", incident.incident_type) self.assertIsNotNone(incident.ended_on)
def test_queue_interrupt_by_contacts(self): jim = self.create_contact("Jim", phone="+12065551212") bob = self.create_contact("Bob", phone="+12065551313") queue_interrupt(self.org, contacts=[jim, bob]) self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "interrupt_sessions", "org_id": self.org.id, "task": {"contact_ids": [jim.id, bob.id]}, "queued_on": matchers.ISODate(), }, )
def test_queue_broadcast(self): jim = self.create_contact("Jim", "+12065551212") bobs = self.create_group("Bobs", [self.create_contact("Bob", "+12065551313")]) bcast = Broadcast.create( self.org, self.admin, { "eng": "Welcome to mailroom!", "spa": "¡Bienvenidx a mailroom!" }, groups=[bobs], contacts=[jim], urns=[jim.urns.get()], base_language="eng", ) with override_settings(TESTING=False): bcast.send() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "send_broadcast", "org_id": self.org.id, "task": { "translations": { "eng": { "text": "Welcome to mailroom!" }, "spa": { "text": "\u00a1Bienvenidx a mailroom!" }, }, "template_state": "legacy", "base_language": "eng", "urns": ["tel:+12065551212"], "contact_ids": [jim.id], "group_ids": [bobs.id], "broadcast_id": bcast.id, "org_id": self.org.id, }, "queued_on": matchers.ISODate(), }, )
def test_queue_flow_start(self): flow = self.get_flow("favorites") jim = self.create_contact("Jim", phone="+12065551212") bobs = self.create_group( "Bobs", [self.create_contact("Bob", phone="+12065551313")]) start = FlowStart.create( flow, self.admin, groups=[bobs], contacts=[jim], urns=["tel:+1234567890", "twitter:bobby"], restart_participants=True, extra={"foo": "bar"}, include_active=True, ) start.async_start() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "start_flow", "org_id": self.org.id, "task": { "start_id": start.id, "start_type": "M", "org_id": self.org.id, "created_by": self.admin.username, "created_by_id": self.admin.id, "flow_id": flow.id, "flow_type": "M", "contact_ids": [jim.id], "group_ids": [bobs.id], "urns": ["tel:+1234567890", "twitter:bobby"], "query": None, "restart_participants": True, "include_active": True, "extra": { "foo": "bar" }, }, "queued_on": matchers.ISODate(), }, )
def assert_contact_queued(self, contact): r = get_redis_connection() # check we have one contact handle event queued for its org self.assertEqual(r.zcard(f"handler:{contact.org.id}"), 1) # load and check that task task = json.loads(r.zrange(f"handler:{contact.org.id}", 0, 1)[0]) self.assertEqual( task, { "type": "handle_contact_event", "org_id": contact.org.id, "task": {"contact_id": contact.id}, "queued_on": matchers.ISODate(), }, )
def test_results_export_finished(self): flow1 = self.create_flow("Test Flow 1") flow2 = self.create_flow("Test Flow 2") export = ExportFlowResultsTask.create( self.org, self.editor, flows=[flow1, flow2], contact_fields=(), responded_only=True, include_msgs=True, extra_urns=(), group_memberships=(), ) export.perform() Notification.export_finished(export) self.assertFalse( self.editor.notifications.get(results_export=export).is_seen) # we only notify the user that started the export self.assert_notifications( after=export.created_on, expected_json={ "type": "export:finished", "created_on": matchers.ISODate(), "target_url": f"/assets/download/results_export/{export.id}/", "is_seen": False, "export": { "type": "results" }, }, expected_users={self.editor}, email=True, ) send_notification_emails() self.assertEqual(1, len(mail.outbox)) self.assertEqual("[Temba] Your results export is ready", mail.outbox[0].subject) self.assertEqual(["*****@*****.**"], mail.outbox[0].recipients()) self.assertIn("Test Flow 1", mail.outbox[0].body) self.assertIn("Test Flow 2", mail.outbox[0].body)
def test_contact_export_finished(self): export = ExportContactsTask.create(self.org, self.editor) export.perform() Notification.export_finished(export) self.assertFalse( self.editor.notifications.get(contact_export=export).is_seen) # we only notify the user that started the export self.assert_notifications( after=export.created_on, expected_json={ "type": "export:finished", "created_on": matchers.ISODate(), "target_url": f"/assets/download/contact_export/{export.id}/", "is_seen": False, "export": { "type": "contact" }, }, expected_users={self.editor}, email=True, ) send_notification_emails() self.assertEqual(1, len(mail.outbox)) self.assertEqual("[Temba] Your contact export is ready", mail.outbox[0].subject) self.assertEqual(["*****@*****.**"], mail.outbox[0].recipients()) # calling task again won't send more emails send_notification_emails() self.assertEqual(1, len(mail.outbox)) # if a user visits the export download page, their notification for that export is now read self.login(self.editor) self.client.get(export.get_download_url()) self.assertTrue( self.editor.notifications.get(contact_export=export).is_seen)
def test_queue_flow_start(self): flow = self.get_flow("favorites") jim = self.create_contact("Jim", "+12065551212") bobs = self.create_group("Bobs", [self.create_contact("Bob", "+12065551313")]) start = FlowStart.create( flow, self.admin, groups=[bobs], contacts=[jim], restart_participants=True, extra={"foo": "bar"}, include_active=True, ) with override_settings(TESTING=False): start.async_start() self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "start_flow", "org_id": self.org.id, "task": { "start_id": start.id, "org_id": self.org.id, "flow_id": flow.id, "flow_type": "M", "contact_ids": [jim.id], "group_ids": [bobs.id], "restart_participants": True, "include_active": True, "extra": { "foo": "bar" }, }, "queued_on": matchers.ISODate(), }, )
def test_tickets_activity(self): # mailroom will create these notifications Notification._create_all(self.org, "tickets:activity", scope="", users=[self.agent, self.editor]) self.assert_notifications( expected_json={ "type": "tickets:activity", "created_on": matchers.ISODate(), "target_url": "/ticket/mine/", "is_seen": False, }, expected_users={self.agent, self.editor}, email=False, ) # if a user visits their assigned tickets page, their notification is now read self.login(self.agent) self.client.get("/ticket/mine/") self.assertTrue(self.agent.notifications.get().is_seen) self.assertFalse(self.editor.notifications.get().is_seen)
def test_from_ticket_event(self): ticketer = Ticketer.create(self.org, self.user, "mailgun", "Email ([email protected])", {}) contact = self.create_contact("Jim", phone="0979111111") ticket = self.create_ticket(ticketer, contact, "Problem", body="Where my shoes?") # event with a user event1 = TicketEvent.objects.create( org=self.org, contact=contact, ticket=ticket, event_type=TicketEvent.TYPE_NOTE, created_by=self.agent, note="this is important", ) self.assertEqual( { "type": "ticket_note_added", "note": "this is important", "assignee": None, "ticket": { "uuid": str(ticket.uuid), "opened_on": matchers.ISODate(), "closed_on": None, "status": "O", "subject": "Problem", "body": "Where my shoes?", "ticketer": { "uuid": str(ticketer.uuid), "name": "Email ([email protected])" }, }, "created_on": matchers.ISODate(), "created_by": { "id": self.agent.id, "first_name": "", "last_name": "", "email": "*****@*****.**" }, }, Event.from_ticket_event(self.org, self.user, event1), ) # event without a user event2 = TicketEvent.objects.create(org=self.org, contact=contact, ticket=ticket, event_type=TicketEvent.TYPE_CLOSED) self.assertEqual( { "type": "ticket_closed", "note": None, "assignee": None, "ticket": { "uuid": str(ticket.uuid), "opened_on": matchers.ISODate(), "closed_on": None, "status": "O", "subject": "Problem", "body": "Where my shoes?", "ticketer": { "uuid": str(ticketer.uuid), "name": "Email ([email protected])" }, }, "created_on": matchers.ISODate(), "created_by": None, }, Event.from_ticket_event(self.org, self.user, event2), )
def test_folder(self, mr_mocks): self.login(self.admin) contact1 = self.create_contact("Joe", phone="123", last_seen_on=timezone.now()) contact2 = self.create_contact("Frank", phone="124", last_seen_on=timezone.now()) contact3 = self.create_contact("Anne", phone="125", last_seen_on=timezone.now()) self.create_contact("Mary No tickets", phone="126", last_seen_on=timezone.now()) self.create_contact("Mr Other Org", phone="126", last_seen_on=timezone.now(), org=self.org2) open_url = reverse("tickets.ticket_folder", kwargs={ "folder": "all", "status": "open" }) closed_url = reverse("tickets.ticket_folder", kwargs={ "folder": "all", "status": "closed" }) mine_url = reverse("tickets.ticket_folder", kwargs={ "folder": "mine", "status": "open" }) unassigned_url = reverse("tickets.ticket_folder", kwargs={ "folder": "unassigned", "status": "open" }) def assert_tickets(resp, tickets: list): actual_tickets = [ t["ticket"]["uuid"] for t in resp.json()["results"] ] expected_tickets = [str(t.uuid) for t in tickets] self.assertEqual(expected_tickets, actual_tickets) # no tickets yet so no contacts returned response = self.client.get(open_url) assert_tickets(response, []) # contact 1 has two open tickets c1_t1 = self.create_ticket(self.mailgun, contact1, "Question 1") # assign it c1_t1.assign(self.admin, assignee=self.admin, note="I've got this") c1_t2 = self.create_ticket(self.mailgun, contact1, "Question 2") self.create_incoming_msg(contact1, "I have an issue") self.create_broadcast(self.admin, "We can help", contacts=[contact1]).msgs.first() # contact 2 has an open ticket and a closed ticket c2_t1 = self.create_ticket(self.mailgun, contact2, "Question 3") c2_t2 = self.create_ticket(self.mailgun, contact2, "Question 4", closed_on=timezone.now()) self.create_incoming_msg(contact2, "Anyone there?") self.create_incoming_msg(contact2, "Hello?") # contact 3 has two closed tickets c3_t1 = self.create_ticket(self.mailgun, contact3, "Question 5", closed_on=timezone.now()) c3_t2 = self.create_ticket(self.mailgun, contact3, "Question 6", closed_on=timezone.now()) # fetching open folder returns all open tickets response = self.client.get(open_url) assert_tickets(response, [c2_t1, c1_t2, c1_t1]) joes_open_tickets = contact1.tickets.filter( status="O").order_by("-opened_on") expected_json = { "results": [ { "uuid": str(contact2.uuid), "name": "Frank", "last_seen_on": matchers.ISODate(), "last_msg": { "text": "Hello?", "direction": "I", "type": "I", "created_on": matchers.ISODate(), "sender": None, }, "ticket": { "uuid": str(contact2.tickets.filter(status="O").first().uuid), "assignee": None, "subject": "Question 3", "last_activity_on": matchers.ISODate(), "closed_on": None, }, }, { "uuid": str(contact1.uuid), "name": "Joe", "last_seen_on": matchers.ISODate(), "last_msg": { "text": "We can help", "direction": "O", "type": "I", "created_on": matchers.ISODate(), "sender": { "id": self.admin.id, "email": "*****@*****.**" }, }, "ticket": { "uuid": str(joes_open_tickets[0].uuid), "assignee": None, "subject": "Question 2", "last_activity_on": matchers.ISODate(), "closed_on": None, }, }, { "uuid": str(contact1.uuid), "name": "Joe", "last_seen_on": matchers.ISODate(), "last_msg": { "text": "We can help", "direction": "O", "type": "I", "created_on": matchers.ISODate(), "sender": { "id": self.admin.id, "email": "*****@*****.**" }, }, "ticket": { "uuid": str(joes_open_tickets[1].uuid), "assignee": { "id": self.admin.id, "first_name": "", "last_name": "", "email": "*****@*****.**", }, "subject": "Question 1", "last_activity_on": matchers.ISODate(), "closed_on": None, }, }, ] } self.assertEqual(expected_json, response.json()) # the two unassigned tickets response = self.client.get(unassigned_url) assert_tickets(response, [c2_t1, c1_t2]) # one assigned ticket for mine response = self.client.get(mine_url) assert_tickets(response, [c1_t1]) # fetching closed folder returns all closed tickets response = self.client.get(closed_url) assert_tickets(response, [c3_t2, c3_t1, c2_t2]) # make sure when paging we get a next url with patch("temba.tickets.views.TicketCRUDL.Folder.paginate_by", 1): response = self.client.get(open_url + "?_format=json") self.assertIsNotNone(response.json()["next"])
def test_from_msg(self): contact1 = self.create_contact("Jim", phone="0979111111") contact2 = self.create_contact("Bob", phone="0979222222") msg_in = self.create_incoming_msg(contact1, "Hello", external_id="12345") self.assertEqual( { "type": "msg_received", "created_on": matchers.ISODate(), "msg": { "uuid": str(msg_in.uuid), "id": msg_in.id, "urn": "tel:+250979111111", "text": "Hello", "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, "external_id": "12345", }, "msg_type": "I", "logs_url": None, }, Event.from_msg(self.org, self.admin, msg_in), ) msg_out = self.create_outgoing_msg(contact1, "Hello", channel=self.channel, status="E", quick_replies=("yes", "no")) log = ChannelLog.objects.create(channel=self.channel, is_error=True, description="Boom", msg=msg_out) msg_out.refresh_from_db() self.assertEqual( { "type": "msg_created", "created_on": matchers.ISODate(), "msg": { "uuid": str(msg_out.uuid), "id": msg_out.id, "urn": "tel:+250979111111", "text": "Hello", "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, "quick_replies": ["yes", "no"], }, "status": "E", "logs_url": f"/channels/channellog/read/{log.id}/", }, Event.from_msg(self.org, self.admin, msg_out), ) ivr_out = self.create_outgoing_msg(contact1, "Hello", msg_type="V") self.assertEqual( { "type": "ivr_created", "created_on": matchers.ISODate(), "msg": { "uuid": str(ivr_out.uuid), "id": ivr_out.id, "urn": "tel:+250979111111", "text": "Hello", "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, }, "status": "S", "logs_url": None, }, Event.from_msg(self.org, self.admin, ivr_out), ) bcast = self.create_broadcast(self.admin, "Hi there", contacts=[contact1, contact2]) msg_out2 = bcast.msgs.filter(contact=contact1).get() self.assertEqual( { "type": "broadcast_created", "created_on": matchers.ISODate(), "translations": { "base": "Hi there" }, "base_language": "base", "msg": { "uuid": str(msg_out2.uuid), "id": msg_out2.id, "urn": "tel:+250979111111", "text": "Hi there", "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, }, "status": "S", "recipient_count": 2, "logs_url": None, }, Event.from_msg(self.org, self.admin, msg_out2), )
def test_flow_event(self, mock_send): self.setupChannel() org = self.channel.org org.save() flow = self.get_flow('color') # replace our uuid of 4 with the right thing actionset = ActionSet.objects.get(x=4) actionset.actions = [ WebhookAction(str(uuid4()), org.get_webhook_url()).as_json() ] actionset.save() # run a user through this flow flow.start([], [self.joe]) # have joe reply with mauve, which will put him in the other category that triggers the API Action sms = self.create_msg(contact=self.joe, direction='I', status='H', text="Mauve", attachments=[ "image/jpeg:http://s3.com/text.jpg", "audio/mp4:http://s3.com/text.mp4" ]) mock_send.return_value = MockResponse(200, "{}") Flow.find_and_handle(sms) # should have one event created event = WebHookEvent.objects.get() self.assertEqual('C', event.status) self.assertEqual(1, event.try_count) self.assertFalse(event.next_attempt) result = WebHookResult.objects.get() self.assertIn("successfully", result.message) self.assertEqual(200, result.status_code) self.assertEqual(self.joe, result.contact) self.assertTrue(mock_send.called) args = mock_send.call_args_list[0][0] prepared_request = args[0] self.assertIn(self.channel.org.get_webhook_url(), prepared_request.url) data = json.loads(prepared_request.body) self.assertEqual(data['channel'], { 'uuid': str(self.channel.uuid), 'name': self.channel.name }) self.assertEqual( data['contact'], { 'uuid': str(self.joe.uuid), 'name': self.joe.name, 'urn': six.text_type(self.joe.get_urn('tel')) }) self.assertEqual(data['flow'], { 'uuid': str(flow.uuid), 'name': flow.name }) self.assertEqual( data['input'], { 'urn': 'tel:+250788123123', 'text': "Mauve", 'attachments': [ "image/jpeg:http://s3.com/text.jpg", "audio/mp4:http://s3.com/text.mp4" ] }) self.assertEqual( data['results'], { 'color': { 'category': 'Other', 'node_uuid': matchers.UUID4String(), 'name': 'color', 'value': 'Mauve', 'created_on': matchers.ISODate(), 'input': 'Mauve\nhttp://s3.com/text.jpg\nhttp://s3.com/text.mp4' } })
def test_channel_alert(self): self.org.add_user( self.editor, OrgRole.ADMINISTRATOR) # upgrade editor to administrator alert1 = Alert.create_and_send(self.channel, Alert.TYPE_POWER) self.assert_notifications( after=alert1.created_on, expected_json={ "type": "channel:alert", "created_on": matchers.ISODate(), "target_url": f"/channels/channel/read/{self.channel.uuid}/", "is_seen": False, "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, }, expected_users={self.admin, self.editor}, email=False, ) # creating another alert for the same channel won't create any new notifications alert2 = Alert.create_and_send(self.channel, Alert.TYPE_POWER) self.assert_notifications(after=alert2.created_on, expected_json={}, expected_users=set(), email=False) # if a user clears their notifications however, they will get new ones for this channel self.admin.notifications.update(is_seen=True) alert3 = Alert.create_and_send(self.channel, Alert.TYPE_POWER) self.assert_notifications( after=alert3.created_on, expected_json={ "type": "channel:alert", "created_on": matchers.ISODate(), "target_url": f"/channels/channel/read/{self.channel.uuid}/", "is_seen": False, "channel": { "uuid": str(self.channel.uuid), "name": "Test Channel" }, }, expected_users={self.admin}, email=False, ) # an alert for a different channel will also create new notifications vonage = self.create_channel("NX", "Vonage", "1234") alert4 = Alert.create_and_send(vonage, Alert.TYPE_POWER) self.assert_notifications( after=alert4.created_on, expected_json={ "type": "channel:alert", "created_on": matchers.ISODate(), "target_url": f"/channels/channel/read/{vonage.uuid}/", "is_seen": False, "channel": { "uuid": str(vonage.uuid), "name": "Vonage" }, }, expected_users={self.admin, self.editor}, email=False, ) # if a user visits the channel read page, their notification for that channel is now read self.login(self.admin) self.client.get( reverse("channels.channel_read", kwargs={"uuid": vonage.uuid})) self.assertTrue(self.admin.notifications.get(channel=vonage).is_seen) self.assertFalse(self.editor.notifications.get(channel=vonage).is_seen)
def test_flow_event(self, mock_send): self.setupChannel() org = self.channel.org org.save() flow = self.get_flow("color") # replace our uuid of 4 with the right thing actionset = ActionSet.objects.get(x=4) actionset.actions = [ WebhookAction(str(uuid4()), org.get_webhook_url()).as_json() ] actionset.save() # run a user through this flow flow.start([], [self.joe]) # have joe reply with mauve, which will put him in the other category that triggers the API Action sms = self.create_msg( contact=self.joe, direction="I", status="H", text="Mauve", attachments=[ "image/jpeg:http://s3.com/text.jpg", "audio/mp4:http://s3.com/text.mp4" ], ) mock_send.return_value = MockResponse(200, "{}") Flow.find_and_handle(sms) # should have one event created event = WebHookEvent.objects.get() self.assertEqual("C", event.status) self.assertEqual(1, event.try_count) self.assertFalse(event.next_attempt) result = WebHookResult.objects.get() self.assertIn("successfully", result.message) self.assertEqual(200, result.status_code) self.assertEqual(self.joe, result.contact) self.assertTrue(mock_send.called) args = mock_send.call_args_list[0][0] prepared_request = args[0] self.assertIn(self.channel.org.get_webhook_url(), prepared_request.url) data = json.loads(prepared_request.body) self.assertEqual(data["channel"], { "uuid": str(self.channel.uuid), "name": self.channel.name }) self.assertEqual( data["contact"], { "uuid": str(self.joe.uuid), "name": self.joe.name, "urn": str(self.joe.get_urn("tel")) }) self.assertEqual(data["flow"], { "uuid": str(flow.uuid), "name": flow.name, "revision": 1 }) self.assertEqual( data["input"], { "urn": "tel:+250788123123", "text": "Mauve", "attachments": [ "image/jpeg:http://s3.com/text.jpg", "audio/mp4:http://s3.com/text.mp4" ], }, ) self.assertEqual( data["results"], { "color": { "category": "Other", "node_uuid": matchers.UUID4String(), "name": "color", "value": "Mauve\nhttp://s3.com/text.jpg\nhttp://s3.com/text.mp4", "created_on": matchers.ISODate(), "input": "Mauve\nhttp://s3.com/text.jpg\nhttp://s3.com/text.mp4", } }, )