def campaign_move_out_of_drafts(self) -> None: self.set_tenant(0) user = self.users[0] factory = TenantsAPIRequestFactory(force_authenticate=user) request = factory.post('', data=dict(name='testing settings')) response = CampaignsViewSet.as_view({'post': 'create'})(request) self.assertEqual(response.status_code, status.HTTP_201_CREATED, str(response.data)) campaign_data = response.data self.assertSetEqual({CampaignProblems.NO_CONTACTS.value, CampaignProblems.NO_STEPS.value}, {p['code'] for p in campaign_data['problems']}) campaign = Campaign.objects.get(id=campaign_data['id']) self.assertSetEqual({CampaignProblems.NO_CONTACTS, CampaignProblems.NO_STEPS}, set(campaign.problems)) contact = Contact.objects.create(email='*****@*****.**') request = factory.post('', data=dict(contact=contact.id)) response = CampaignsParticipationViewSet.as_view({'post': 'create'})( request, **{compose_parent_pk_kwarg_name('campaign'): campaign_data['id']} ) self.assertEqual(response.status_code, status.HTTP_201_CREATED, str(response.data)) participation_data = response.data self.assertEqual(ParticipationStatus.ACTIVE.value, participation_data['status']) campaign.refresh_from_db() self.assertListEqual([CampaignProblems.NO_STEPS], campaign.problems) request = factory.post('', data=dict( weekdays=[Weekdays.Monday.value, ], start=datetime.time(8, 0, 0, 0), end=datetime.time(18, 0, 0, 0), )) response = StepViewSet.as_view({'post': 'create'})( request, **{compose_parent_pk_kwarg_name('campaign'): campaign.id, } ) self.assertEqual(response.status_code, status.HTTP_201_CREATED, str(response.data)) step_data = response.data self.assertListEqual([StepProblems.EMPTY_STEP.value], [p['code'] for p in step_data['problems']]) campaign.refresh_from_db() self.assertListEqual([CampaignProblems.EMPTY_STEP], campaign.problems) request = factory.post('', data=dict( subject='Hi {{first_name}}', html_content='{{first_name|default:"Human"}}, where are you? ', )) response = EmailStageViewSet.as_view({'post': 'create'})( request, **{ compose_parent_pk_kwarg_name('step__campaign'): campaign.id, compose_parent_pk_kwarg_name('step'): step_data['id'], } ) self.assertEqual(response.status_code, status.HTTP_201_CREATED, str(response.data)) campaign.refresh_from_db() self.assertFalse(campaign.problems) self.assertFalse(any([s.problems for s in campaign.steps.all()])) self.assertEqual(CampaignStatus.PAUSED, campaign.status)
def get_custom_regex_parent_lookup(self, parent_pk_kwarg_name, parent_lookup_value_regex): """ Build parent lookup regex with custom regular expression. """ return self.get_custom_regex_lookup( compose_parent_pk_kwarg_name(parent_pk_kwarg_name), parent_lookup_value_regex )
def test_bulk_add_to_folder(self) -> None: self.set_tenant(0) first_template = EmailTemplate.objects.create( owner=self.user, subject='First Subject {{ name }}', content='First Content {{ name }}') second_template = EmailTemplate.objects.create( owner=self.user, subject='Second Subject {{ name }}', content='SecondContent {{ name }}') third_template = EmailTemplate.objects.create( owner=self.user, subject='Third Subject {{ name }}', content='Third Content {{ name }}') folder = Folder.objects.create(name='best templates') folder.templates.add(third_template) factory = TenantsRequestFactory(force_authenticate=self.user) request = factory.patch( '', json.dumps([ dict(id=first_template.id), dict(id=second_template.id), ]), content_type='application/json', ) force_authenticate(request, user=self.user) response = NestedFolderEmailTemplateViewSet.as_view({ 'patch': 'partial_bulk_update', })(request, **{ compose_parent_pk_kwarg_name('folder'): folder.id }) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.data)) templates_data = response.data self.assertEqual(2, len(templates_data)) self.assertSetEqual({ first_template.id, second_template.id, }, {t['id'] for t in templates_data}) folder.refresh_from_db() templates = folder.templates.all() self.assertSetEqual( { first_template.id, second_template.id, third_template.id, }, {c.id for c in templates})
def test_bulk_add_to_list(self) -> None: self.set_tenant(0) first_contact = Contact.objects.create(email='*****@*****.**', first_name='First', last_name='Smith') second_contact = Contact.objects.create(email='*****@*****.**', first_name='Second', last_name='Smith') third_contact = Contact.objects.create(email='*****@*****.**', first_name='Third', last_name='Smith') contact_list = ContactList.objects.create(name='people') contact_list.contacts.add(third_contact) factory = TenantsRequestFactory(force_authenticate=self.user) request = factory.patch( '', json.dumps([ dict(id=first_contact.id), dict(id=second_contact.id), ]), content_type='application/json', ) force_authenticate(request, user=self.user) response = NestedContactListContactViewSet.as_view({ 'patch': 'partial_bulk_update', })(request, **{ compose_parent_pk_kwarg_name('lists'): contact_list.id }) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.data)) contacts_data = response.data self.assertTrue(2, len(contacts_data)) self.assertSetEqual({ first_contact.id, second_contact.id, }, {c['id'] for c in contacts_data}) contact_list.refresh_from_db() contacts = contact_list.contacts.all() self.assertSetEqual( { first_contact.id, second_contact.id, third_contact.id, }, {c.id for c in contacts})
def get_parent_prefix(self, parents_query_lookups): prefix = '/' current_item = self i = len(parents_query_lookups) - 1 while current_item: prefix = '{parent_prefix}/(?P<{parent_pk_kwarg_name}>[^/.]+)/{prefix}'.format( parent_prefix=current_item.parent_prefix, parent_pk_kwarg_name=compose_parent_pk_kwarg_name(parents_query_lookups[i]), prefix=prefix ) i -= 1 current_item = current_item.parent_item return prefix.strip('/')
def get_parent_prefix(self, parents_query_lookups): prefix = '/' current_item = self i = len(parents_query_lookups) - 1 parent_lookup_value_regex = getattr(self.parent_viewset, 'lookup_value_regex', '[^/.]+') while current_item: prefix = '{parent_prefix}/(?P<{parent_pk_kwarg_name}>{parent_lookup_value_regex})/{prefix}'.format( parent_prefix=current_item.parent_prefix, parent_pk_kwarg_name=compose_parent_pk_kwarg_name(parents_query_lookups[i]), parent_lookup_value_regex=parent_lookup_value_regex, prefix=prefix ) i -= 1 current_item = current_item.parent_item return prefix.strip('/')
def get_parent_prefix(self, parents_query_lookups): prefix = '/' current_item = self i = len(parents_query_lookups) - 1 while current_item: parent_lookup_value_regex = getattr(current_item.parent_viewset, 'lookup_value_regex', '[^/.]+') prefix = '{parent_prefix}/(?P<{parent_pk_kwarg_name}>{parent_lookup_value_regex})/{prefix}'.format( parent_prefix=current_item.parent_prefix, parent_pk_kwarg_name=compose_parent_pk_kwarg_name(parents_query_lookups[i]), parent_lookup_value_regex=parent_lookup_value_regex, prefix=prefix ) i -= 1 current_item = current_item.parent_item return prefix.strip('/')
def test_bulk_remove_from_folder(self) -> None: self.set_tenant(0) first_template = EmailTemplate.objects.create( owner=self.user, subject='First Subject {{ name }}', content='First Content {{ name }}') second_template = EmailTemplate.objects.create( owner=self.user, subject='Second Subject {{ name }}', content='SecondContent {{ name }}') third_template = EmailTemplate.objects.create( owner=self.user, subject='Third Subject {{ name }}', content='Third Content {{ name }}') folder = Folder.objects.create(name='other templates') folder.templates.add( *[first_template, second_template, third_template]) factory = TenantsRequestFactory(force_authenticate=self.user) request = factory.delete( '', content_type='application/json', QUERY_STRING=urlencode({ 'id__in': ','.join([ str(first_template.id), str(second_template.id), ]) }), ) force_authenticate(request, user=self.user) response = NestedFolderEmailTemplateViewSet.as_view( {'delete': 'bulk_destroy'})(request, **{ compose_parent_pk_kwarg_name('folder'): folder.id }) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT, str(response.data)) folder.refresh_from_db() templates = folder.templates.all() self.assertListEqual([ third_template.id, ], [c.id for c in templates])
def test_email_sending(self) -> None: self.set_tenant(0) user = self.users[0] kwargs = _generate_email_account_kwargs() EmailAccount.objects.create(user=user, email='*****@*****.**', **kwargs) contact = Contact.objects.create(email='*****@*****.**', first_name='Bob', last_name='Smith') factory = TenantsAPIRequestFactory(force_authenticate=user) request = factory.post('', data=dict( subject='single email', sender='some name', html_content='{{first_name}}, <b>thank</b> you for reply!', track_opening=True )) with patch( 'campaigns.providers.models.SmtpConnectionSettings.get_connection' ) as mocked_get_connection: mocked_get_connection.return_value = LocmemEmailBackend() response = NestedContactEmailMessageViewSet.as_view( {'post': 'create'} )(request, **{compose_parent_pk_kwarg_name('contact'): contact.id}) self.assertEqual(status.HTTP_201_CREATED, response.status_code, str(response.data)) self.assertEqual(len(mail.outbox), 1) msg = mail.outbox[0] self.assertEqual('single email', msg.subject) self.assertEqual('some name <*****@*****.**>', msg.from_email) self.assertListEqual(['*****@*****.**'], msg.to) msg_id = msg.extra_headers.get('Message-ID') self.assertIsNotNone(msg_id) inbox_message = Message.objects.get(message_id=msg_id) email_data = response.data self.assertEqual('single email', email_data['subject']) self.assertEqual('some name <*****@*****.**>', email_data['from_header']) self.assertEqual('*****@*****.**', email_data['to_header']) self.assertEqual(inbox_message.id, email_data['id']) self.assertTrue(email_data['outgoing']) self.assertIsNone(email_data['in_reply_to']) r = r'<html><body>Bob, <b>thank</b> you for reply!<img src="http://127.0.0.1:8000/.*"></body></html>' self.assertRegex(email_data['html_content'], r)
def test_steps_validation_during_patching(self) -> None: self.set_tenant(0) user = self.users[0] campaign = Campaign.objects.create(name='start/stop validation', owner=user) step = Step.objects.create(campaign=campaign, start=datetime.time(9, 45), end=datetime.time(18, 30)) factory = TenantsAPIRequestFactory(force_authenticate=user) request = factory.patch('', data=dict(timezone='UTC-0300')) response = StepViewSet.as_view({'patch': 'partial_update'})(request, **{ compose_parent_pk_kwarg_name('campaign'): campaign.id, 'pk': step.pk }) self.assertEqual(response.status_code, status.HTTP_200_OK, str(response.data)) step_data = response.data self.assertEqual(step.id, step_data['id']) self.assertEqual('UTC-0300', step_data['timezone'])
def test_bulk_remove_from_list(self) -> None: self.set_tenant(0) first_contact = Contact.objects.create(email='*****@*****.**', first_name='First', last_name='Smith') second_contact = Contact.objects.create(email='*****@*****.**', first_name='Second', last_name='Smith') third_contact = Contact.objects.create(email='*****@*****.**', first_name='Third', last_name='Smith') contact_list = ContactList.objects.create(name='people') contact_list.contacts.add( *[first_contact, second_contact, third_contact]) factory = TenantsRequestFactory(force_authenticate=self.user) request = factory.delete( '', content_type='application/json', QUERY_STRING=urlencode({ 'id__in': ','.join([ str(first_contact.id), str(second_contact.id), ]) }), ) force_authenticate(request, user=self.user) response = NestedContactListContactViewSet.as_view( {'delete': 'bulk_destroy'})(request, **{ compose_parent_pk_kwarg_name('lists'): contact_list.id }) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT, str(response.data)) contact_list.refresh_from_db() contacts = contact_list.contacts.all() self.assertListEqual([ third_contact.id, ], [c.id for c in contacts])
def get_parent_prefix(self, parents_query_lookups): prefix = "/" current_item = self i = len(parents_query_lookups) - 1 while current_item: parent_lookup_value_regex = getattr(current_item.parent_viewset, "lookup_value_regex", "[^/.]+") prefix = ("{parent_prefix}/(?P<{parent_pk_kwarg_name}>" "{parent_lookup_value_regex})/{prefix}" "".format( parent_prefix=current_item.parent_prefix, parent_pk_kwarg_name=compose_parent_pk_kwarg_name( parents_query_lookups[i]), parent_lookup_value_regex=parent_lookup_value_regex, prefix=prefix, )) i -= 1 current_item = current_item.parent_item return prefix.strip("/")
def get_parent_prefix(self, parents_query_lookups): """ Allow every character in parent prefix except for / (to separate url parts). """ prefix = '/' current_item = self i = len(parents_query_lookups) - 1 while current_item: lookup_value = getattr(current_item.viewset_breadcrumb[-1], 'lookup_value_regex', '[^/]+') prefix = '{parent_prefix}/(?P<{parent_pk_kwarg_name}>{lookup_value})/{prefix}'.format( parent_prefix=current_item.parent_prefix, parent_pk_kwarg_name=compose_parent_pk_kwarg_name( parents_query_lookups[i]), lookup_value=lookup_value, prefix=prefix) i -= 1 current_item = current_item.parent_item return prefix.strip('/')
def get_parent_lookup_regex(self, value): return '(?P<{0}>[^/.]+)'.format(compose_parent_pk_kwarg_name(value))
def get_parent_lookup_regex(self, value): return get_lookup_allowed_symbols(compose_parent_pk_kwarg_name(value), force_dot=True)
def get_parent_lookup_regex(self, value): return '(?P<{0}>[^/.]+)'.format(compose_parent_pk_kwarg_name(value))
def get_parent_lookup_regex(self, value): return get_lookup_allowed_symbols(compose_parent_pk_kwarg_name(value), force_dot=True)
def __init__(self, view_name=None, **kwargs): self.parent_lookup_field = kwargs.pop('parent_lookup_field') self.parent_lookup_url_kwarg = kwargs.pop('parent_lookup_url_kwarg', compose_parent_pk_kwarg_name(self.parent_lookup_field)) super(ParentLinkedIdentityField, self).__init__(view_name, **kwargs)