def contact_field(contact, arg): field = ContactField.get_by_key(contact.org, arg.lower()) if field is None: return MISSING_VALUE value = contact.get_field_display(field) return value or MISSING_VALUE
def test_views(self): # update the planting date for our contacts self.farmer1.set_field(self.user, "planting_date", "1/10/2020") # get the resulting time (including minutes) planting_date = self.farmer1.get_field_value(self.planting_date) # don't log in, try to create a new campaign response = self.client.get(reverse("campaigns.campaign_create")) self.assertRedirect(response, reverse("users.user_login")) # ok log in as an org self.login(self.admin) # go to to the creation page response = self.client.get(reverse("campaigns.campaign_create")) self.assertEqual(200, response.status_code) # groups shouldn't include the group that isn't ready self.assertEqual( set(response.context["form"].fields["group"].queryset), {self.farmers}) post_data = dict(name="Planting Reminders", group=self.farmers.pk) response = self.client.post(reverse("campaigns.campaign_create"), post_data) # should redirect to read page for this campaign campaign = Campaign.objects.get() self.assertRedirect( response, reverse("campaigns.campaign_read", args=[campaign.pk])) # go to the list page, should be there as well response = self.client.get(reverse("campaigns.campaign_list")) self.assertContains(response, "Planting Reminders") # try searching for the campaign by group name response = self.client.get( reverse("campaigns.campaign_list") + "?search=farmers") self.assertContains(response, "Planting Reminders") # test no match response = self.client.get( reverse("campaigns.campaign_list") + "?search=factory") self.assertNotContains(response, "Planting Reminders") # archive a campaign post_data = dict(action="archive", objects=campaign.pk) self.client.post(reverse("campaigns.campaign_list"), post_data) response = self.client.get(reverse("campaigns.campaign_list")) self.assertNotContains(response, "Planting Reminders") # restore the campaign response = self.client.get(reverse("campaigns.campaign_archived")) self.assertContains(response, "Planting Reminders") post_data = dict(action="restore", objects=campaign.pk) self.client.post(reverse("campaigns.campaign_archived"), post_data) response = self.client.get(reverse("campaigns.campaign_archived")) self.assertNotContains(response, "Planting Reminders") response = self.client.get(reverse("campaigns.campaign_list")) self.assertContains(response, "Planting Reminders") # test viewers cannot use action archive or restore self.client.logout() # create a viewer self.viewer = self.create_user("Viewer") self.org.viewers.add(self.viewer) self.viewer.set_org(self.org) self.login(self.viewer) # go to the list page, should be there as well response = self.client.get(reverse("campaigns.campaign_list")) self.assertContains(response, "Planting Reminders") # cannot archive a campaign post_data = dict(action="archive", objects=campaign.pk) self.client.post(reverse("campaigns.campaign_list"), post_data) response = self.client.get(reverse("campaigns.campaign_list")) self.assertContains(response, "Planting Reminders") response = self.client.get(reverse("campaigns.campaign_archived")) self.assertNotContains(response, "Planting Reminders") self.client.logout() self.login(self.admin) # see if we can create a new event, should see both sms and voice flows response = self.client.get( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk) self.assertContains(response, self.reminder_flow.name) self.assertContains(response, self.voice_flow.name) self.assertEqual(200, response.status_code) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=-1, base="", direction="A", offset=2, unit="D", event_type="M", flow_to_start=self.reminder_flow.pk, ) response = self.client.post( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk, post_data) self.assertTrue(response.context["form"].errors) self.assertIn("A message is required", str(response.context["form"].errors["__all__"])) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=-1, base="allo!" * 500, direction="A", offset=2, unit="D", event_type="M", flow_to_start=self.reminder_flow.pk, ) response = self.client.post( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk, post_data) self.assertTrue(response.context["form"].errors) self.assertTrue( "Translation for 'Default' exceeds the %d character limit." % Msg.MAX_TEXT_LEN in str( response.context["form"].errors["__all__"])) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=-1, base="", direction="A", offset=2, unit="D", event_type="F", ) response = self.client.post( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk, post_data) self.assertTrue(response.context["form"].errors) self.assertIn("Please select a flow", response.context["form"].errors["flow_to_start"]) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=-1, base="", direction="A", offset=2, unit="D", event_type="F", flow_to_start=self.reminder_flow.pk, ) response = self.client.post( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk, post_data) # should be redirected back to our campaign read page self.assertRedirect( response, reverse("campaigns.campaign_read", args=[campaign.pk])) # should now have a campaign event event = CampaignEvent.objects.get() self.assertEqual(self.reminder_flow, event.flow) self.assertEqual(self.planting_date, event.relative_to) self.assertEqual(2, event.offset) # read the campaign read page response = self.client.get( reverse("campaigns.campaign_read", args=[campaign.pk])) self.assertContains(response, "Reminder Flow") self.assertContains(response, "1") # convert our planting date to UTC and calculate with our offset utc_planting_date = planting_date.astimezone(pytz.utc) scheduled_date = utc_planting_date + timedelta(days=2) # should also have event fires scheduled for our contacts fire = EventFire.objects.get() self.assertEqual(scheduled_date.hour, fire.scheduled.hour) self.assertEqual(scheduled_date.minute, fire.scheduled.minute) self.assertEqual(scheduled_date.day, fire.scheduled.day) self.assertEqual(scheduled_date.month, fire.scheduled.month) self.assertEqual(scheduled_date.year, fire.scheduled.year) self.assertEqual(event, fire.event) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=15, base="", direction="A", offset=1, unit="D", event_type="F", flow_to_start=self.reminder_flow.pk, ) response = self.client.post( reverse("campaigns.campaignevent_update", args=[event.pk]), post_data) # should be redirected back to our campaign event read page self.assertRedirect( response, reverse("campaigns.campaignevent_read", args=[event.pk])) # should now have update the campaign event event = CampaignEvent.objects.get() self.assertEqual(self.reminder_flow, event.flow) self.assertEqual(self.planting_date, event.relative_to) self.assertEqual(1, event.offset) # should also event fires rescheduled for our contacts fire = EventFire.objects.get() self.assertEqual(13, fire.scheduled.hour) self.assertEqual(0, fire.scheduled.minute) self.assertEqual(0, fire.scheduled.second) self.assertEqual(0, fire.scheduled.microsecond) self.assertEqual(2, fire.scheduled.day) self.assertEqual(10, fire.scheduled.month) self.assertEqual(2020, fire.scheduled.year) self.assertEqual(event, fire.event) post_data = dict( relative_to=self.planting_date.pk, delivery_hour=15, base="", direction="A", offset=2, unit="D", event_type="F", flow_to_start=self.reminder2_flow.pk, ) self.client.post( reverse("campaigns.campaignevent_create") + "?campaign=%d" % campaign.pk, post_data) # trying to archive our flow should fail since it belongs to a campaign post_data = dict(action="archive", objects=[self.reminder_flow.pk]) response = self.client.post(reverse("flows.flow_list"), post_data) self.reminder_flow.refresh_from_db() self.assertFalse(self.reminder_flow.is_archived) self.assertEqual( "Reminder Flow is used inside a campaign. To archive it, first remove it from your campaigns.", response.get("Temba-Toast"), ) post_data = dict( action="archive", objects=[self.reminder_flow.pk, self.reminder2_flow.pk]) response = self.client.post(reverse("flows.flow_list"), post_data) self.assertEqual( "Planting Reminder and Reminder Flow are used inside a campaign. To archive them, first remove them from your campaigns.", response.get("Temba-Toast"), ) for e in CampaignEvent.objects.filter(flow=self.reminder2_flow.pk): e.release() # archive the campaign post_data = dict(action="archive", objects=campaign.pk) self.client.post(reverse("campaigns.campaign_list"), post_data) response = self.client.get(reverse("campaigns.campaign_list")) self.assertNotContains(response, "Planting Reminders") # should have no event fires self.assertFalse(EventFire.objects.all()) # restore the campaign post_data = dict(action="restore", objects=campaign.pk) self.client.post(reverse("campaigns.campaign_archived"), post_data) # EventFire should be back self.assertTrue(EventFire.objects.all()) # set a planting date on our other farmer self.farmer2.set_field(self.user, "planting_date", "1/6/2022") # should have two fire events now fires = EventFire.objects.all() self.assertEqual(2, len(fires)) fire = fires[0] self.assertEqual(2, fire.scheduled.day) self.assertEqual(10, fire.scheduled.month) self.assertEqual(2020, fire.scheduled.year) self.assertEqual(event, fire.event) fire = fires[1] self.assertEqual(2, fire.scheduled.day) self.assertEqual(6, fire.scheduled.month) self.assertEqual(2022, fire.scheduled.year) self.assertEqual(event, fire.event) # setting a planting date on our outside contact has no effect self.nonfarmer.set_field(self.user, "planting_date", "1/7/2025") self.assertEqual(2, EventFire.objects.all().count()) # remove one of the farmers from the group response = self.client.post( reverse("contacts.contact_read", args=[self.farmer1.uuid]), dict(contact=self.farmer1.pk, group=self.farmers.pk), ) self.assertEqual(200, response.status_code) # should only be one event now (on farmer 2) fire = EventFire.objects.get() self.assertEqual(2, fire.scheduled.day) self.assertEqual(6, fire.scheduled.month) self.assertEqual(2022, fire.scheduled.year) self.assertEqual(event, fire.event) # but if we add him back in, should be updated post_data = dict(name=self.farmer1.name, groups=[self.farmers.id], __urn__tel=self.farmer1.get_urn("tel").path) planting_date_field = ContactField.get_by_key(self.org, "planting_date") self.client.post( reverse("contacts.contact_update", args=[self.farmer1.id]), post_data) response = self.client.post( reverse("contacts.contact_update_fields", args=[self.farmer1.id]), dict(contact_field=planting_date_field.id, field_value="4/8/2020"), ) self.assertRedirect( response, reverse("contacts.contact_read", args=[self.farmer1.uuid])) fires = EventFire.objects.all() self.assertEqual(2, len(fires)) fire = fires[0] self.assertEqual(5, fire.scheduled.day) self.assertEqual(8, fire.scheduled.month) self.assertEqual(2020, fire.scheduled.year) self.assertEqual(event, fire.event) self.assertEqual(str(fire), "%s - %s" % (fire.event, fire.contact)) event = CampaignEvent.objects.filter(is_active=True).first() # get the detail page of the event response = self.client.get( reverse("campaigns.campaignevent_read", args=[event.pk])) self.assertEqual(200, response.status_code) self.assertEqual(response.context["scheduled_event_fires_count"], 0) self.assertEqual(len(response.context["scheduled_event_fires"]), 2) # delete the event self.client.post( reverse("campaigns.campaignevent_delete", args=[event.pk]), dict()) self.assertFalse(CampaignEvent.objects.all().exists()) response = self.client.get( reverse("campaigns.campaign_read", args=[campaign.pk])) self.assertNotContains(response, "Color Flow")