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)
Exemple #2
0
 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})
Exemple #4
0
    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('/')
Exemple #6
0
 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('/')
Exemple #7
0
 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'])
Exemple #11
0
    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])
Exemple #12
0
 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("/")
Exemple #13
0
    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('/')
Exemple #14
0
 def get_parent_lookup_regex(self, value):
     return '(?P<{0}>[^/.]+)'.format(compose_parent_pk_kwarg_name(value))
Exemple #15
0
 def get_parent_lookup_regex(self, value):
     return get_lookup_allowed_symbols(compose_parent_pk_kwarg_name(value), force_dot=True)
Exemple #16
0
 def get_parent_lookup_regex(self, value):
     return '(?P<{0}>[^/.]+)'.format(compose_parent_pk_kwarg_name(value))
Exemple #17
0
 def get_parent_lookup_regex(self, value):
     return get_lookup_allowed_symbols(compose_parent_pk_kwarg_name(value),
                                       force_dot=True)
Exemple #18
0
 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)