示例#1
0
    def test_not_disabled(self):
        """
        An anonymous user who provides the :verify: query string or
        user with is_disabled set to True should be redirected to the home
        page. An anonymous user who does not should see a 404. A user with
        is_active set to False should proceed to their destination.
        """
        client = TestClient()
        user = UserFactory(email="*****@*****.**")

        # Anonymous user
        resp = client.get(reverse('view_profile'))
        path = resp.request.get('PATH_INFO')
        self.assertRedirects(resp, reverse('home') + '?next=' + path)

        # This is ugly, but it is an artifact of the way Django redirects
        # users who fail the `user_passes_test` decorator.
        qs = '?verify=%s' % user.user_guid
        next_qs = '?next=' + urlquote('/profile/view/%s' % qs)

        # Anonymous user navigates to url with :verify: in query string
        resp = client.get(reverse('view_profile') + qs)
        # Old path + qs is urlquoted and added to the url as the :next: param
        self.assertRedirects(resp, "http://testserver/" + next_qs)

        # Active user
        client.login_user(user)
        resp = client.get(reverse('view_profile'))
        self.assertTrue(resp.status_code, 200)

        # Disabled user
        user.is_disabled = True
        user.save()
        resp = client.get(reverse('view_profile'))
        self.assertRedirects(resp, "http://testserver/?next=/profile/view/")
class SavedSearchTemplateTagTests(MyJobsBase):
    def setUp(self):
        super(SavedSearchTemplateTagTests, self).setUp()
        self.user = UserFactory(is_active=True)
        self.search = SavedSearchFactory(user=self.user)

    def test_confirm_creation_active_user(self):
        expected = reverse('view_full_feed') + '?id={id}&verify={guid}'.format(
            id=self.search.pk, guid=self.user.user_guid)
        actual = get_created_url(self.search)

        self.assertEqual(actual, expected)

    def test_confirm_creation_inactive_user(self):
        self.user.is_active = False
        self.user.save()

        user_with_profile = UserFactory(email='*****@*****.**',
                                        is_active=False)
        profile_search = SavedSearchFactory(user=user_with_profile)
        ActivationProfile.objects.create(user=user_with_profile,
                                         email=user_with_profile.email)

        for saved_search in [self.search, profile_search]:
            actual = get_created_url(saved_search)

            profile = ActivationProfile.objects.get(user=saved_search.user)
            expected = reverse('registration_activate',
                               args=[profile.activation_key]) + \
                '?verify={guid}'.format(guid=saved_search.user.user_guid)
            self.assertEqual(actual, expected)
示例#3
0
    def test_search_updates_facet_counts(self):
        # Add ProfileData to the candidate_user
        EducationFactory(user=self.candidate_user)
        AddressFactory(user=self.candidate_user)
        LicenseFactory(user=self.candidate_user)
        self.candidate_user.save()

        # Create a new user with ProfileData
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        EducationFactory(user=user)
        AddressFactory(user=user)
        LicenseFactory(user=user)
        user.save()

        update_solr_task(settings.TEST_SOLR_INSTANCE)

        # Assert there are two users with country codes
        country_tag = '#Country-details-table .facet-count'
        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 2)

        # When we search, the facet count updates.
        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='find')
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 1)
示例#4
0
    def test_not_disabled(self):
        """
        An anonymous user who provides the :verify: query string or
        user with is_disabled set to True should be redirected to the home
        page. An anonymous user who does not should see a 404. A user with
        is_active set to False should proceed to their destination.
        """
        client = TestClient()
        user = UserFactory()

        #Anonymous user
        resp = client.get(reverse('view_profile'))
        path = resp.request.get('PATH_INFO')
        self.assertRedirects(resp, reverse('home') + '?next=' + path)

        # This is ugly, but it is an artifact of the way Django redirects
        # users who fail the `user_passes_test` decorator.
        qs = '?verify=%s' % user.user_guid
        next_qs = '?next=' + urlquote('/profile/view/%s' % qs)

        # Anonymous user navigates to url with :verify: in query string
        resp = client.get(reverse('view_profile') + qs)
        # Old path + qs is urlquoted and added to the url as the :next: param
        self.assertRedirects(resp, "http://testserver/" + next_qs)

        # Active user
        client.login_user(user)
        resp = client.get(reverse('view_profile'))
        self.assertTrue(resp.status_code, 200)

        #Disabled user
        user.is_disabled = True
        user.save()
        resp = client.get(reverse('view_profile'))
        self.assertRedirects(resp, "http://testserver/?next=/profile/view/")
class NewUserTests(SeleniumTestCase):

    """Tests Account creation"""

    def setUp(self):
        self.user = UserFactory(first_name="John", last_name="Doe")

    def test_home_page_works(self):
        """
        As John, navigating to https://secure.my.jobs should send me to a page
        titled "My.jobs".
        """
        self.browser.get(self.live_server_url)
        self.assertIn(self.browser.title, 'My.jobs')

    def test_cant_log_in_without_account(self):
        """
        As John, I shouldn't be able to log into My.jobs without registering
        first.
        """
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # attempt to log in
        username = self.find('id_username')
        username.send_keys(self.user.email)
        self.find('id_password').send_keys(self.user.password)
        self.find('login').click()

        self.assertEqual(username.get_attribute('placeholder'),
                         'Please enter a correct email.')

    def test_user_registration(self):
        """
        As John, I should be able to register on My.jobs and log in.
        """
        user = UserFactory.build(email='*****@*****.**')
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # register
        self.find('id_email').send_keys(user.email)
        self.find('id_password1').send_keys(user.password)
        self.find('id_password2').send_keys(user.password)
        self.find('register').click()

        self.assertEqual(self.find('profile').get_attribute(
            'innerHTML'),
            'Skip: Take me to my profile')

    def test_user_login(self):
        self.user.set_password("test")
        self.user.save()
        self.find('id_username').send_keys(self.user.email)
        self.find('id_password').send_keys("test")
        self.find('login').click()
示例#6
0
    def test_presave_ignore(self):
        user = UserFactory(email="*****@*****.**")
        update_solr_task(self.test_solr)

        user.last_login = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)
        user.save()

        self.assertEqual(Update.objects.all().count(), 0)

        user.last_login = datetime.datetime(2013, 8, 15, 8, 15, 12, 0, pytz.UTC)
        user.email = "[email protected]"
        user.save()

        self.assertEqual(Update.objects.all().count(), 1)
class RedirectMiddlewareTests(MyJobsBase):
    def setUp(self):
        super(RedirectMiddlewareTests, self).setUp()
        self.user = UserFactory()
        self.redirect_middleware = PasswordChangeRedirectMiddleware()
        self.request_factory = RequestFactory()

    def test_logged_in_no_redirect(self):
        """
        A logged in user whose password_change flag is not set
        should proceed to their original destination
        """
        request = self.request_factory.get(reverse('edit_account'))
        request.user = self.user
        response = self.redirect_middleware.process_request(request)
        self.assertEqual(response, None)

    def test_logged_in_autocreated_user_redirects(self):
        """
        A logged in user whose password_change flag is set should
        be redirected to the password change form
        """
        self.user.password_change = True
        self.user.save()

        request = self.request_factory.get(reverse('saved_search_main'))
        request.user = self.user

        response = self.redirect_middleware.process_request(request)

        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.get('location'),
                         reverse('edit_account')+"#as-password")

    def test_not_logged_in_returns_forbidden(self):
        """
        An anonymous user that tries to post to a private url should
        receive a 403 Forbidden status
        """
        request = self.request_factory.get(reverse('saved_search_main'),
                                           HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        new_request = request.GET.copy()
        new_request['next'] = reverse('home')
        request.GET = new_request
        request.REQUEST.dicts = (new_request, request.POST)
        request.user = AnonymousUser()
        response = self.redirect_middleware.process_request(request)
        self.assertEqual(response.status_code, 403)
示例#8
0
class RedirectMiddlewareTests(TestCase):
    def setUp(self):
        self.user = UserFactory()
        self.redirect_middleware = RedirectMiddleware()
        self.request_factory = RequestFactory()

    def test_logged_in_no_redirect(self):
        """
        A logged in user whose password_change flag is not set
        should proceed to their original destination
        """
        request = self.request_factory.get(reverse('edit_account'))
        request.user = self.user
        response = self.redirect_middleware.process_request(request)
        self.assertEqual(response, None)

    def test_logged_in_autocreated_user_redirects(self):
        """
        A logged in user whose password_change flag is set should
        be redirected to the password change form
        """
        self.user.password_change = True
        self.user.save()

        request = self.request_factory.get(reverse('saved_search_main'))
        request.user = self.user

        response = self.redirect_middleware.process_request(request)

        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.get('location'),
                         reverse('edit_account'))

    def test_not_logged_in_returns_forbidden(self):
        """
        An anonymous user that tries to post to a private url should
        receive a 403 Forbidden status
        """
        request = self.request_factory.get(reverse('saved_search_main'),
                                           HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        new_request = request.GET.copy()
        new_request['next'] = reverse('home')
        request.GET = new_request
        request.REQUEST.dicts = (new_request, request.POST)
        request.user = AnonymousUser()
        response = self.redirect_middleware.process_request(request)
        self.assertEqual(response.status_code, 403)
示例#9
0
    def test_search_domain(self):
        """We should be able to search for domain."""
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='shouldWork.com')
        url = reverse('dashboard') + q

        response = self.client.post(url)
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 1)
示例#10
0
    def test_inactive_user_sees_message(self):
        """
        A user with is_verified or is_active set to False should see an
        activation message instead of the content they were originally meaning
        to see.
        """
        client = TestClient(path=reverse('saved_search_main'))
        user = UserFactory()

        # Active user
        client.login_user(user)
        resp = client.get()
        self.assertIn('Saved Search', resp.content)

        # Inactive user
        user.is_verified= False
        user.save()
        resp = client.get()
        self.assertIn('unavailable', resp.content)
示例#11
0
    def test_inactive_user_sees_message(self):
        """
        A user with is_verified or is_active set to False should see an
        activation message instead of the content they were originally meaning
        to see.
        """
        client = TestClient(path=reverse('saved_search_main'))
        user = UserFactory(email="*****@*****.**")

        # Active user
        client.login_user(user)
        resp = client.get()
        self.assertIn('Saved Search', resp.content)

        # Inactive user
        user.is_verified = False
        user.save()
        resp = client.get()
        self.assertIn('unavailable', resp.content)
示例#12
0
文件: models.py 项目: jpaezsa/MyJobs
    def test_is_active(self):
        """
        A user with is_active set to False should be redirected to the home
        page, while a user with is_active set to True should proceed to their
        destination.
        """
        client = TestClient()
        user = UserFactory()
        quoted_email = urllib.quote(user.email)

        # Active user
        client.login_user(user)
        resp = client.get(reverse('saved_search_main'))
        self.assertTrue(resp.status_code, 200)

        # Inactive user
        user.is_active = False
        user.save()
        resp = client.get(reverse('saved_search_main'))
        self.assertRedirects(resp, "http://testserver/?next=/saved-search/view/")
示例#13
0
class AdminTests(MyJobsBase):
    def setUp(self):
        super(AdminTests, self).setUp()
        self.site = AdminSite()
        settings.SITE = SeoSite.objects.first()
        self.request = RequestFactory().get("/")
        self.user = UserFactory(is_superuser=True)
        self.request.user = self.user

    def test_admin_request_form(self):
        """
        The forms used by ValueEventAdmin and CronEventAdmin should have the
        current request as attributes.
        """
        for Admin, Model in [(ValueEventAdmin, ValueEvent), (CronEventAdmin, CronEvent)]:
            admin = Admin(Model, self.site)
            form = admin.get_form(self.request)()
            self.assertEqual(form.request, self.request)

    def test_non_superuser_form(self):
        """
        The email_template queryset should have an appropriate WHERE clause
        if the current user is not a company user.
        """
        company = CompanyUserFactory(user=self.user).company
        admin = ValueEventAdmin(ValueEvent, self.site)

        for superuser in [True, False]:
            self.user.is_superuser = superuser
            self.user.save()
            form = admin.get_form(self.request)()
            email_template = form.fields["email_template"]
            query = str(email_template.queryset.query)
            if superuser:
                self.assertFalse("WHERE" in query)
            else:
                if connection.vendor == "sqlite":
                    test = 'WHERE ("myemails_emailtemplate"."owner_id" = %s'
                else:
                    test = "WHERE (`myemails_emailtemplate`.`owner_id` = %s"
                self.assertTrue(test % company.pk in query)
示例#14
0
    def test_is_active(self):
        """
        A user with is_active set to False should be redirected to the home
        page, while a user with is_active set to True should proceed to their
        destination.
        """
        client = TestClient()
        user = UserFactory()
        quoted_email = urllib.quote(user.email)

        # Active user
        client.login_user(user)
        resp = client.get(reverse('saved_search_main'))
        self.assertTrue(resp.status_code, 200)

        # Inactive user
        user.is_active = False
        user.save()
        resp = client.get(reverse('saved_search_main'))
        self.assertRedirects(resp,
                             "http://testserver/?next=/saved-search/view/")
示例#15
0
    def test_group_status(self):
        """
        Should return True if user.groups contains the group specified and
        False if it does not.
        """
        user = UserFactory()

        user.groups.all().delete()

        for group in Group.objects.all():
            # Makes a list of all group names, excluding the one that the
            # user will be a member of
            names = map(lambda group: group.name,
                        Group.objects.filter(~Q(name=group.name)))

            user.groups.add(group.pk)
            user.save()

            for name in names:
                self.assertFalse(User.objects.is_group_member(user, name))
            self.assertTrue(User.objects.is_group_member(user, group.name))

            user.groups.all().delete()
示例#16
0
    def test_group_status(self):
        """
        Should return True if user.groups contains the group specified and
        False if it does not.
        """
        client = TestClient()
        user = UserFactory()

        user.groups.all().delete()

        for group in Group.objects.all():
            # Makes a list of all group names, excluding the one that the
            # user will be a member of
            names = map(lambda group: group.name,
                        Group.objects.filter(~Q(name=group.name)))

            user.groups.add(group.pk)
            user.save()

            for name in names:
                self.assertFalse(User.objects.is_group_member(user, name))
            self.assertTrue(User.objects.is_group_member(user, group.name))

            user.groups.all().delete()
示例#17
0
class SavedSearchModelsTests(MyJobsBase):
    def setUp(self):
        super(SavedSearchModelsTests, self).setUp()
        self.user = UserFactory()

        self.patcher = patch('urllib2.urlopen', return_file())
        self.mock_urlopen = self.patcher.start()

    def tearDown(self):
        super(SavedSearchModelsTests, self).tearDown()
        try:
            self.patcher.stop()
        except RuntimeError:
            # patcher was stopped in a test
            pass

    def test_send_search_email(self):
        SavedSearchDigestFactory(user=self.user,
                                 is_active=False)
        search = SavedSearchFactory(user=self.user, is_active=True,
                                    frequency='D',
                                    url='www.my.jobs/jobs?q=new+search')
        send_search_digests()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual(email.subject, search.label)
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)
        self.assertNotEqual(email.body.find(search.url),
                            -1,
                            "Search url was not found in email body")
        self.assertTrue("Your resume is %s%% complete" %
                        self.user.profile_completion in email.body)

    def test_send_search_digest_email(self):
        SavedSearchDigestFactory(user=self.user)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 0)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('No saved searches' in log.reason)
        self.assertFalse(log.was_sent)

        search1 = SavedSearchFactory(user=self.user)
        self.assertIsNone(SavedSearch.objects.get(pk=search1.pk).last_sent)
        send_search_digests()
        self.assertIsNotNone(SavedSearch.objects.get(pk=search1.pk).last_sent)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 2)
        log = SavedSearchLog.objects.last()
        self.assertTrue(log.was_sent)

        search2 = SavedSearchFactory(user=self.user)
        self.assertIsNone(SavedSearch.objects.get(pk=search2.pk).last_sent)
        send_search_digests()
        self.assertIsNotNone(SavedSearch.objects.get(pk=search2.pk).last_sent)
        self.assertEqual(len(mail.outbox), 2)
        self.assertEqual(SavedSearchLog.objects.count(), 3)
        log = SavedSearchLog.objects.last()
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual(email.subject, "Your Saved Search Digest")
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)

    def test_send_search_digest_send_if_none(self):
        SavedSearchDigestFactory(user=self.user, send_if_none=True)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 0)

        SavedSearchFactory(user=self.user)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 1)
    
    def test_initial_email(self):
        search = SavedSearchFactory(user=self.user, is_active=False,
                                    url='www.my.jobs/search?q=new+search')
        search.initial_email()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('Jobs are not sent' in log.reason)
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual("My.jobs New Saved Search" in email.subject, True)
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)
        # Search url appears twice - once displaying the saved search source
        # and once in the view link.
        self.assertEqual(email.body.count(search.url), 2)

    def test_send_update_email(self):
        search = SavedSearchFactory(user=self.user, is_active=False,
                                    url='www.my.jobs/search?q=new+search')
        search.send_update_email('Your search is updated')
        self.assertEqual(len(mail.outbox), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('Jobs are not sent' in log.reason)
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual("My.jobs Saved Search Updated" in email.subject, True)
        self.assertTrue("table" in email.body)
        self.assertTrue("Your search is updated" in email.body)
        self.assertTrue(email.to[0] in email.body)

    def test_saved_search_all_jobs_link(self):
        search = SavedSearchFactory(user=self.user)
        search.send_email()

        email = mail.outbox.pop()
        # When search.url does not start with my.jobs, use it as the all jobs
        # link
        self.assertFalse(search.url.startswith('http://my.jobs'))
        self.assertNotEqual(email.body.find(search.url), -1)

        # When search.url starts with my.jobs, strip /feed/rss from search.feed
        # if it exists and use that as the all jobs link
        search.url = 'http://my.jobs/' + '1'*32
        search.save()
        search.send_email()
        email = mail.outbox.pop()
        self.assertEqual(email.body.find(search.url),
                         -1)
        self.assertNotEqual(email.body.find(search.feed.replace('/feed/rss', '')),
                            -1)

    def assert_modules_in_hrefs(self, modules):
        """
        Assert that each module in :modules: is in the set of HTML elements
        matched by li > a in an email
        """
        email = mail.outbox.pop()
        soup = BeautifulSoup(email.body)
        lis = soup.findAll('li')

        # .attrs is a dictionary, where the key is the attribute
        hrefs = [li.find('a').attrs['href'] for li in lis]

        self.assertEqual(len(hrefs), len(modules))

        # We can do self because the list of modules in settings and the list
        # of recommendations should be in the same order
        mapping = zip(modules, hrefs)
        for pair in mapping:
            # Saved search emails should have one li per required profile unit
            # that the owner does not currently have
            self.assertTrue(pair[0] in pair[1].lower())

    def test_email_profile_completion(self):

        search = SavedSearchFactory(user=self.user)
        search.send_email()
        self.assertEqual(len(settings.PROFILE_COMPLETION_MODULES), 6)
        self.assert_modules_in_hrefs(settings.PROFILE_COMPLETION_MODULES)

        PrimaryNameFactory(user=self.user)

        search.send_email()

        new_modules = [module for module in settings.PROFILE_COMPLETION_MODULES
                       if module != 'name']
        self.assertEqual(len(new_modules), 5)
        self.assert_modules_in_hrefs(new_modules)

    def test_email_contains_activate_link(self):
        search = SavedSearchFactory(user=self.user)
        self.assertTrue(self.user.is_active)
        search.send_email()
        email = mail.outbox.pop()
        self.assertFalse('activate your account' in email.body)

        self.user.is_active = False
        self.user.save()
        search.send_email()
        email = mail.outbox.pop()
        self.assertTrue('activate your account' in email.body)

    def test_fix_fixable_search(self):
        self.patcher.stop()
        SavedSearchDigestFactory(user=self.user)
        search = SavedSearchFactory(user=self.user, feed='')
        self.assertFalse(search.feed)

        # Celery raises a retry that makes the test fail. In reality
        # everything is fine, so ignore the retry-fail.
        try:
            send_search_digests()
        except RetryTaskError:
            pass
        self.assertEqual(len(mail.outbox), 0)

        search = SavedSearch.objects.get(pk=search.pk)
        self.assertTrue(search.is_active)
        self.assertTrue(search.feed)

    def test_disable_bad_search(self):
        self.patcher.stop()
        SavedSearchDigestFactory(user=self.user)
        search = SavedSearchFactory(user=self.user, feed='',
                                    url='http://example.com')
        self.assertFalse(search.feed)

        # Celery raises a retry that makes the test fail. In reality
        # everything is fine, so ignore the retry-fail.
        try:
            send_search_digests()
        except RetryTaskError:
            pass

        email = mail.outbox.pop()
        search = SavedSearch.objects.get(pk=search.pk)
        self.assertFalse(search.is_active)

        self.assertTrue('has failed URL validation' in email.body)

    def test_get_unsent_jobs(self):
        """
        When sending a saved search email, we should retrieve all new jobs since
        last send, not all new jobs based on frequency.
        """
        self.patcher.stop()
        self.patcher = patch('urllib2.urlopen',
                             return_file(time_=datetime.datetime.now() -
                                         datetime.timedelta(days=3)))
        self.mock_urlopen = self.patcher.start()
        last_sent = datetime.datetime.now() - datetime.timedelta(days=3)
        search = SavedSearchFactory(frequency='D',
                                    last_sent=last_sent,
                                    user=self.user,
                                    email=self.user.email)
        search.send_email()
        self.assertEqual(len(mail.outbox), 1)

    def test_inactive_user_receives_saved_search(self):
        self.assertEqual(len(mail.outbox), 0)
        self.user.is_active = False
        self.user.save()
        saved_search = SavedSearchFactory(user=self.user)
        saved_search.send_email()
        self.assertEqual(len(mail.outbox), 1)

    def test_saved_search_no_jobs(self):
        search = SavedSearchFactory(feed='http://google.com', user=self.user)
        search.send_email()

        self.assertEqual(len(mail.outbox), 0)

    def test_saved_search_digest_no_jobs(self):
        self.digest = SavedSearchDigestFactory(user=self.user, is_active=True)

        for x in range(0, 5):
            SavedSearchFactory(user=self.user, feed='http://google.com')

        self.digest.send_email()
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('saved searches have no jobs' in log.reason)
        self.assertFalse(log.was_sent)

        self.assertEqual(len(mail.outbox), 0)
示例#18
0
class SavedSearchModelsTests(MyJobsBase):
    def setUp(self):
        super(SavedSearchModelsTests, self).setUp()
        self.user = UserFactory()

        self.patcher = patch('urllib2.urlopen', return_file())
        self.mock_urlopen = self.patcher.start()

    def tearDown(self):
        super(SavedSearchModelsTests, self).tearDown()
        try:
            self.patcher.stop()
        except RuntimeError:
            # patcher was stopped in a test
            pass

    def test_send_search_email(self):
        SavedSearchDigestFactory(user=self.user,
                                 is_active=False)
        search = SavedSearchFactory(user=self.user, is_active=True,
                                    frequency='D',
                                    url='www.my.jobs/jobs?q=new+search')
        send_search_digests()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual(email.subject, search.label)
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)
        self.assertNotEqual(email.body.find(search.url),
                            -1,
                            "Search url was not found in email body")
        self.assertTrue("Your profile is %s%% complete" %
                        self.user.profile_completion in email.body)

    def requeue(self, search, digest):
        """
        Asserts that the given search has a last_sent of None and there are no
        emails in mail.outbox. Requeues the provided search and then asserts
        that last_sent was updated and a mail was sent if the provided digest is
        not active, otherwise reasserts that last_sent is None and no emails
        have been sent.
        """
        self.assertIsNone(search.last_sent)
        self.assertEqual(len(mail.outbox), 0)
        requeue_missed_searches()
        search = SavedSearch.objects.get(pk=search.pk)
        date = datetime.date.today()
        outbox_count = 1
        if digest.is_active:
            date = None
            outbox_count = 0

        self.assertEqual(search.last_sent.date() if search.last_sent else None,
                         date)
        self.assertEqual(len(mail.outbox), outbox_count)

    def test_requeue_weekly_saved_search(self):
        """
        Tests that weekly saved searches are requeued correctly individually in
        addition to as part of a digest.
        """
        today = datetime.date.today().isoweekday()
        two_days_ago = today - 2
        if two_days_ago <= 0:
            two_days_ago += 7
        digest = SavedSearchDigestFactory(user=self.user,
                                          is_active=True)
        search = SavedSearchFactory(user=self.user, is_active=True,
                                    frequency='W', day_of_week=two_days_ago)

        self.requeue(search, digest)

        digest.is_active = False
        digest.save()
        search.last_sent = None
        search.save()
        mail.outbox = []

        self.requeue(search, digest)

    def test_requeue_monthly_saved_search(self):
        """
        Tests that monthly saved searches are requeued correctly individually
        in addition to as part of a digest.
        """
        today = datetime.date.today().day
        last_week = today - 7
        if last_week <= 0:
            last_week += 31
        digest = SavedSearchDigestFactory(user=self.user,
                                          is_active=True)
        search = SavedSearchFactory(user=self.user, is_active=True,
                                    frequency='M', day_of_month=last_week)

        self.requeue(search, digest)

        digest.is_active = False
        digest.save()
        search.last_sent = None
        search.save()
        mail.outbox = []

        self.requeue(search, digest)

    def test_send_search_digest_email(self):
        SavedSearchDigestFactory(user=self.user)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 0)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('No saved searches' in log.reason)
        self.assertFalse(log.was_sent)

        search1 = SavedSearchFactory(user=self.user)
        self.assertIsNone(search1.last_sent)
        send_search_digests()
        self.assertIsNotNone(SavedSearch.objects.get(pk=search1.pk).last_sent)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 2)
        log = SavedSearchLog.objects.last()
        self.assertTrue(log.was_sent)

        search2 = SavedSearchFactory(user=self.user)
        self.assertIsNone(search2.last_sent)
        send_search_digests()
        self.assertIsNotNone(SavedSearch.objects.get(pk=search2.pk).last_sent)
        self.assertEqual(len(mail.outbox), 2)
        self.assertEqual(SavedSearchLog.objects.count(), 3)
        log = SavedSearchLog.objects.last()
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual(email.subject, "Your Saved Search Digest")
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)

    def test_send_search_digest_send_if_none(self):
        SavedSearchDigestFactory(user=self.user, send_if_none=True)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 0)

        SavedSearchFactory(user=self.user)
        send_search_digests()
        self.assertEqual(len(mail.outbox), 1)
    
    def test_initial_email(self):
        search = SavedSearchFactory(user=self.user, is_active=False,
                                    url='www.my.jobs/search?q=new+search')
        search.initial_email()
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('Jobs are not sent' in log.reason)
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual("My.jobs New Saved Search" in email.subject, True)
        self.assertTrue("table" in email.body)
        self.assertTrue(email.to[0] in email.body)
        # Search url appears twice - once displaying the saved search source
        # and once in the view link.
        self.assertEqual(email.body.count(search.url), 2)

    def test_send_update_email(self):
        search = SavedSearchFactory(user=self.user, is_active=False,
                                    url='www.my.jobs/search?q=new+search')
        search.send_update_email('Your search is updated')
        self.assertEqual(len(mail.outbox), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('Jobs are not sent' in log.reason)
        self.assertTrue(log.was_sent)

        email = mail.outbox.pop()
        self.assertEqual(email.from_email, 'My.jobs Saved Search <*****@*****.**>')
        self.assertEqual(email.to, [self.user.email])
        self.assertEqual("My.jobs Saved Search Updated" in email.subject, True)
        self.assertTrue("table" in email.body)
        self.assertTrue("Your search is updated" in email.body)
        self.assertTrue(email.to[0] in email.body)

    def test_saved_search_all_jobs_link(self):
        search = SavedSearchFactory(user=self.user)
        search.send_email()

        email = mail.outbox.pop()
        # When search.url does not start with my.jobs, use it as the all jobs
        # link
        self.assertFalse(search.url.startswith('http://my.jobs'))
        self.assertNotEqual(email.body.find(search.url), -1)

        # When search.url starts with my.jobs, strip /feed/rss from search.feed
        # if it exists and use that as the all jobs link
        search.url = 'http://my.jobs/' + '1'*32
        search.save()
        search.send_email()
        email = mail.outbox.pop()
        self.assertEqual(email.body.find(search.url),
                         -1)
        self.assertNotEqual(
            email.body.find(search.feed.replace('/feed/rss', '')), -1)

    def test_unicode_in_saved_search(self):
        """Tests that saved search urls with unicode don't cause errors."""
        search = SavedSearchFactory(
            user=self.user, 
            url=u"warehouse.jobs/search?location=Roswell%2C+GA&q=Delivery+I"
                "+%E2%80%93+Material+Handler%2FDriver+Helper+%E2%80%93+3rd"
                "+Shift%2C+Part-time")

        try:
            search.send_email()
        except UnicodeEncodeError as e:
            self.fail(e)

    def test_pss_contact_record_tagged(self):
        """
        When a contact record is created from a saved search being sent, that
        record should have the saved search's tag.
        """

        company = CompanyFactory()
        partner = PartnerFactory(owner=company)
        tag = TagFactory(name="Test Tag")
        search = PartnerSavedSearchFactory(
            user=self.user, created_by=self.user, provider=company,
            partner=partner)
        search.tags.add(tag)

        search.send_email()
        record = ContactRecord.objects.get(tags__name=tag.name)
        self.assertTrue(record.contactlogentry.successful)

    @patch('mysearches.models.send_email')
    def test_send_pss_fails(self, mock_send_email):
        """
        When a partner saved search fails to send, we should not imply
        that it was successful.
        """
        company = CompanyFactory()
        partner = PartnerFactory(owner=company)
        search = PartnerSavedSearchFactory(user=self.user, created_by=self.user,
                                           provider=company, partner=partner)

        e = SMTPAuthenticationError(418, 'Toot toot')
        mock_send_email.side_effect = e

        self.assertEqual(ContactRecord.objects.count(), 0)
        self.assertEqual(SavedSearchLog.objects.count(), 0)
        search.send_email()

        record = ContactRecord.objects.get()
        log = SavedSearchLog.objects.get()
        self.assertFalse(log.was_sent)
        self.assertEqual(log.reason, "Toot toot")
        self.assertTrue(record.notes.startswith(log.reason))
        self.assertFalse(record.contactlogentry.successful)

    def assert_modules_in_hrefs(self, modules):
        """
        Assert that each module in :modules: is in the set of HTML elements
        matched by li > a in an email
        """
        email = mail.outbox.pop()
        soup = BeautifulSoup(email.body)
        lis = soup.findAll('li')

        # .attrs is a dictionary, where the key is the attribute
        hrefs = [li.find('a').attrs['href'] for li in lis]

        self.assertEqual(len(hrefs), len(modules))

        # We can do self because the list of modules in settings and the list
        # of recommendations should be in the same order
        mapping = zip(modules, hrefs)
        for pair in mapping:
            # Saved search emails should have one li per required profile unit
            # that the owner does not currently have
            self.assertTrue(pair[0] in pair[1].lower())

    def test_email_profile_completion(self):

        search = SavedSearchFactory(user=self.user)
        search.send_email()
        self.assertEqual(len(settings.PROFILE_COMPLETION_MODULES), 6)
        self.assert_modules_in_hrefs(settings.PROFILE_COMPLETION_MODULES)

        PrimaryNameFactory(user=self.user)

        search.send_email()

        new_modules = [module for module in settings.PROFILE_COMPLETION_MODULES
                       if module != 'name']
        self.assertEqual(len(new_modules), 5)
        self.assert_modules_in_hrefs(new_modules)

    def test_email_contains_activate_link(self):
        search = SavedSearchFactory(user=self.user)
        self.assertTrue(self.user.is_active)
        search.send_email()
        email = mail.outbox.pop()
        self.assertFalse('activate your account' in email.body)

        self.user.is_active = False
        self.user.save()
        search.send_email()
        email = mail.outbox.pop()
        self.assertTrue('activate your account' in email.body)

    def test_errors_dont_disable_searches(self):
        """
        We should retry sending saved searches but exceeding our maximum
        number of retries should not disable those searches.
        """
        self.mock_urlopen.side_effect = ValueError("bork bork bork")

        SavedSearchDigestFactory(user=self.user)
        search = SavedSearchFactory(user=self.user, feed='www.my.jobs')

        # Celery raises a retry that makes the test fail. In reality
        # everything is fine, so ignore the retry.
        try:
            send_search_digests()
        except RetryTaskError:
            pass
        self.assertEqual(len(mail.outbox), 0)

        search = SavedSearch.objects.get(pk=search.pk)
        self.assertTrue(search.is_active)

    def test_get_unsent_jobs(self):
        """
        When sending a saved search email, we should retrieve all new jobs since
        last send, not all new jobs based on frequency.
        """
        self.patcher.stop()
        self.patcher = patch('urllib2.urlopen',
                             return_file(time_=datetime.datetime.now() -
                                         datetime.timedelta(days=3)))
        self.mock_urlopen = self.patcher.start()
        last_sent = datetime.datetime.now() - datetime.timedelta(days=3)
        search = SavedSearchFactory(frequency='D',
                                    last_sent=last_sent,
                                    user=self.user,
                                    email=self.user.email)
        search.send_email()
        self.assertEqual(len(mail.outbox), 1)

    def test_inactive_user_receives_saved_search(self):
        self.assertEqual(len(mail.outbox), 0)
        self.user.is_active = False
        self.user.save()
        saved_search = SavedSearchFactory(user=self.user)
        saved_search.send_email()
        self.assertEqual(len(mail.outbox), 1)

    def test_saved_search_no_jobs(self):
        search = SavedSearchFactory(feed='http://google.com', user=self.user)
        search.send_email()

        self.assertEqual(len(mail.outbox), 0)

    def test_saved_search_digest_no_jobs(self):
        self.digest = SavedSearchDigestFactory(user=self.user, is_active=True)

        for x in range(0, 5):
            SavedSearchFactory(user=self.user, feed='http://google.com')

        self.digest.send_email()
        self.assertEqual(SavedSearchLog.objects.count(), 1)
        log = SavedSearchLog.objects.get()
        self.assertTrue('saved searches have no jobs' in log.reason)
        self.assertFalse(log.was_sent)

        self.assertEqual(len(mail.outbox), 0)
示例#19
0
文件: views.py 项目: jpaezsa/MyJobs
class MyDashboardViewsTests(TestCase):
    def setUp(self):
        self.staff_user = UserFactory()
        group = Group.objects.get(name=CompanyUser.GROUP_NAME)
        self.staff_user.groups.add(group)
        self.staff_user.save()

        self.company = CompanyFactory()
        self.company.save()
        self.admin = CompanyUserFactory(user=self.staff_user,
                                        company=self.company)
        self.admin.save()
        self.microsite = MicrositeFactory(company=self.company)
        self.microsite.save()

        self.client = TestClient()
        self.client.login_user(self.staff_user)

        self.candidate_user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=self.candidate_user,
                           url='http://test.jobs/search?q=django',
                           label='test Jobs')
        self.candidate_user.save()

        for i in range(5):
            # Create 5 new users
            user = UserFactory(email='*****@*****.**' % i)
            for search in SEARCH_OPTS:
                # Create 15 new searches and assign three per user
                SavedSearchFactory(user=user,
                                   url='http://test.jobs/search?q=%s' % search,
                                   label='%s Jobs' % search)

    def test_number_of_searches_and_users_is_correct(self):
        response = self.client.post(
            reverse('dashboard') + '?company=' + str(self.company.id),
            {'microsite': 'test.jobs'})
        soup = BeautifulSoup(response.content)
        # 10 searches total, two rows per search
        self.assertEqual(len(soup.select('#row-link-table tr')), 20)

        old_search = SavedSearch.objects.all()[0]
        old_search.created_on -= timedelta(days=31)
        old_search.save()

        response = self.client.post(
            reverse('dashboard') + '?company=' + str(self.company.id),
            {'microsite': 'test.jobs'})
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 20)

    # Tests to see if redirect from /candidates/ goes to candidates/view/
    def test_redirect_to_candidates_views_default_page(self):
        response = self.client.post('/candidates/')

        # response returns HttpResponsePermanentRedirect which returns a 301
        # status code instead of the normal 302 redirect status code
        self.assertRedirects(response,
                             '/candidates/view/',
                             status_code=301,
                             target_status_code=200)

        response = self.client.post(reverse('dashboard'))

        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content)
        company_name = soup.find('h1')
        company_name = company_name.next

        self.assertEqual(company_name, self.company.name)

    # Eventually these opted-in/out will be changed to
    # track if user is part of company's activity feed
    def test_candidate_has_opted_in(self):
        response = self.client.post(
            reverse('candidate_information', ) + '?company=' +
            str(self.company.id) + '&user='******'candidate_information', ) + '?company=' +
            str(self.company.id) + '&user='******'candidate_information', ) + '?company=' +
            str(self.company.id) + '&user='******'div', {
            'id': 'candidate-content'
        }).findAll('a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 6)
        self.assertEqual(len(info), 16)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_with_activites(self):
        response = self.client.post(
            reverse('candidate_information', ) + '?company=' +
            str(self.company.id) + '&user='******'div', {
            'id': 'candidate-content'
        }).findAll('a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 1)
        self.assertEqual(len(info), 3)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_and_activites(self):
        saved_search = SavedSearch.objects.get(user=self.candidate_user)
        saved_search.delete()
        response = self.client.post(
            reverse('candidate_information', ) + '?company=' +
            str(self.company.id) + '&user='******'div', {'id': 'candidate-content'})

        self.assertFalse(info)
        self.assertEqual(response.status_code, 404)

    def test_export_csv(self):
        response = self.client.post(
            reverse('export_candidates') + '?company=' + str(self.company.id) +
            '&ex-t=csv')
        self.assertTrue(response.content)
        self.assertEqual(response.status_code, 200)

    def test_export_pdf(self):
        response = self.client.post(
            reverse('export_candidates') + '?company=' + str(self.company.id) +
            '&ex-t=pdf')
        self.assertTrue(response.content.index('PDF'))
        self.assertEqual(response.templates[0].name,
                         'mydashboard/export/candidate_listing.html')
        self.assertEqual(response.status_code, 200)

    def test_export_xml(self):
        response = self.client.post(
            reverse('export_candidates') + '?company=' + str(self.company.id) +
            '&ex-t=xml')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_export_json(self):
        response = self.client.post(
            reverse('export_candidates') + '?company=' + str(self.company.id) +
            '&ex-t=json')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)
示例#20
0
class NewUserTests(SeleniumTestCase):
    """Tests Account creation"""
    def setUp(self):
        super(NewUserTests, self).setUp()
        company = CompanyFactory()
        self.user = UserFactory(first_name="John", last_name="Doe")
        admin_role = RoleFactory(company=company, name='Admin')
        self.user.roles.add(self.admin_role)

    def test_home_page_works(self):
        """
        As John, navigating to https://secure.my.jobs should send me to a page
        titled "My.jobs".
        """
        self.browser.get(self.live_server_url)
        self.assertIn(self.browser.title, 'My.jobs')

    def test_cant_log_in_without_account(self):
        """
        As John, I shouldn't be able to log into My.jobs without registering
        first.
        """
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # We're trying to access a private page while unauthenticated, which
        # should result in a next parameter being added.
        self.assertTrue('next=' in self.browser.current_url)

        # attempt to log in
        username = self.find('id_username')
        username.send_keys(self.user.email)
        self.find('id_password').send_keys(self.user.password)
        self.find('login').click()

        # If we've logged in, the next parameter should have went away. We
        # aren't expecting to be logged in right now as the password was bad.
        self.assertTrue('next=' in self.browser.current_url)

    def test_user_registration(self):
        """
        As John, I should be able to register on My.jobs and log in.
        """
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # register
        self.find('id_email').send_keys('*****@*****.**')
        self.find('id_password1').send_keys('aaAA11..')
        self.find('id_password2').send_keys('aaAA11..')
        self.find('register').click()

        try:
            WebDriverWait(self.browser, 10).until(
                expected_conditions.presence_of_element_located(
                    (By.ID, 'profile')))
        finally:
            self.assertEqual(
                self.find('profile').get_attribute('innerHTML'),
                'Skip: Take me to my profile')

    def test_user_login(self):
        self.user.set_password("test")
        self.user.save()
        self.find('id_username').send_keys(self.user.email)
        self.find('id_password').send_keys("test")
        self.find('login').click()
示例#21
0
class MyJobsAdminTests(MyJobsBase):
    def setUp(self):
        super(MyJobsAdminTests, self).setUp()
        self.user.set_password('5UuYquA@')
        self.user.is_superuser = True
        self.user.save()
        self.account_owner = UserFactory(email='*****@*****.**')
        SeoSiteFactory(domain='secure.my.jobs')
        mail.outbox = []

        self.data = {
            '_selected_action': [unicode(self.account_owner.pk)],
            'action': 'request_account_access'
        }

    def test_request_access_to_staff(self):
        """
        Requesting access to a staff/superuser account is not allowed.
        """
        self.account_owner.is_staff = True
        self.account_owner.save()

        # Selecting the action in the User changelist and pressing "OK" should
        # immediately show a notification at the top of the page.
        response = self.client.post(reverse('admin:myjobs_user_changelist'),
                                    self.data,
                                    follow=True)
        self.assertEqual(len(mail.outbox), 0)
        self.assertContains(response, ("Requesting access to staff or "
                                       "superusers is not supported."))

        # Manually constructing a post to the relevant url should redirect
        # to the User changelist and not send notification emails.
        response = self.client.post(
            reverse('request-account-access',
                    kwargs={'uid': self.account_owner.pk}),
            {'reason': 'reason here'})

        self.assertRedirects(response, reverse('admin:myjobs_user_changelist'))
        self.assertEqual(len(mail.outbox), 0)

    def test_request_access_to_non_staff(self):
        """
        Requesting access to a non-staff/superuser account succeeds if the
        target is not a staff/superuser account and the requesting staff
        member provides a reason.
        """
        # Request access to an account to get to the request form.
        response = self.client.post(reverse('admin:myjobs_user_changelist'),
                                    self.data,
                                    follow=True)
        self.assertContains(response,
                            "What is the nature of this request?",
                            msg_prefix="Did not redirect to the request form")
        url = reverse('request-account-access',
                      kwargs={'uid': self.account_owner.pk})
        last_redirect = response.redirect_chain[-1][0]

        # If the admin action determines that it is valid, it redirects. Ensure
        # we redirected to the expected location.
        self.assertTrue(last_redirect.endswith(url),
                        msg="Did not redirect as expected")

        # Try submitting the request form without a reason.
        response = self.client.post(url)
        self.assertContains(response,
                            "This field is required.",
                            msg_prefix=("Form error not present on invalid "
                                        "submission"))
        self.assertEqual(len(mail.outbox),
                         0,
                         msg="Mail sent despite form errors")

        # # Submit again, providing a reason.
        self.client.post(url, {'reason': 'reason here'})
        self.assertEqual(len(mail.outbox),
                         1,
                         msg="Mail did not send on successful form submission")
        email = mail.outbox[0]
        self.assertTrue(self.account_owner.email in email.to,
                        msg="Email was sent to the wrong user")
        self.assertTrue('reason here' in email.body,
                        msg="Account access reason was not in the sent email")

    def test_export_as_csv_admin_action(self):
        """
        Tests the ability to export the list of destination manipulations as a
        CSV.

        """
        email = '*****@*****.**'
        password = '******'
        UserFactory(email=email,
                    password=password,
                    is_staff=True,
                    is_superuser=True)
        # only superusers are allowed to use Django amin
        self.client.login(username=email, password=password)

        manipulations = [
            DestinationManipulationFactory(view_source=i)
            for i in range(200, 210)
        ]
        # this is the format we expect results to be in if deserializing CSV
        # into a list of dicts
        formatted_manipulations = [{
            u'View Source': unicode(m.view_source),
            u'View Source Name': '',
            u'BUID': unicode(m.buid),
            u'Action Type': unicode(m.action_type),
            u'Value 1': unicode(m.value_1),
            u'Value 2': unicode(m.value_2),
            u'Action': unicode(m.action)
        } for m in manipulations]

        args = {
            'action': 'export_as_csv',
            '_selected_action': [unicode(m.pk) for m in manipulations[:5]]
        }
        changelist_url = reverse(
            "admin:redirect_destinationmanipulation_changelist")

        # asking to export as csv when selected items should serialize only
        # those items
        response = self.client.post(changelist_url, args)
        reader = csv.DictReader(response.content.split('\r\n'))
        self.assertItemsEqual(list(reader), formatted_manipulations[:5])

        args['select_across'] = '1'

        # choosing "select all" should export all records in the queryset,
        # regardless of the list of selected items passed
        response = self.client.post(changelist_url, args)
        reader = csv.DictReader(response.content.split('\r\n'))
        self.assertItemsEqual(list(reader), formatted_manipulations)
示例#22
0
class SavedSearchHelperTests(MyJobsBase):
    def setUp(self):
        super(SavedSearchHelperTests, self).setUp()
        self.user = UserFactory()
        self.valid_url = 'http://www.my.jobs/jobs?location=chicago&q=nurse'

        self.patcher = patch('urllib2.urlopen', return_file())
        self.patcher.start()

    def tearDown(self):
        super(SavedSearchHelperTests, self).tearDown()
        self.patcher.stop()

    def test_valid_dotjobs_url(self):
        url, soup = validate_dotjobs_url(self.valid_url, self.user)
        self.assertIsNotNone(url)
        self.assertIsNotNone(soup)

        no_netloc = 'www.my.jobs/jobs?location=chicago&q=nurse'
        title, url = validate_dotjobs_url(no_netloc, self.user)
        self.assertIsNotNone(title)
        self.assertIsNotNone(url)
        expected = urlparse(
            'http://www.my.jobs/jobs/feed/rss?q=nurse&location=chicago')
        actual = urlparse(url.replace('amp;', ''))
        self.assertEqual(actual.path, expected.path)
        self.assertEqual(parse_qs(actual.query), parse_qs(expected.query))

        valid_filter_url = 'www.my.jobs/jobs/'
        title, url = validate_dotjobs_url(valid_filter_url, self.user)
        self.assertIsNotNone(title)
        self.assertIsNotNone(url)

    def test_validate_dotjobs_url_with_special_chars(self):
        urls = [
            ('http://www.my.jobs/jobs/?q=query with spaces',
             'http://www.my.jobs/jobs/feed/rss?q=query+with+spaces'),
            ('http://www.my.jobs/jobs/?q=яы',
             'http://www.my.jobs/jobs/feed/rss?q=%D1%8F%D1%8B')
        ]
        for url_set in urls:
            label, feed = validate_dotjobs_url(url_set[0], self.user)
            self.assertEqual(feed, url_set[1])
            self.assertIsNotNone(label)

    def test_invalid_dotjobs_url(self):
        urls = ['http://google.com',  # url does not contain a feed
                '',  # url not provided
                'http://']  # invalid url provided
        for url in urls:
            title, url = validate_dotjobs_url(url, self.user)
            self.assertIsNone(title)
            self.assertIsNone(url)

    def test_date_in_range(self):
        start = datetime.date(month=1, day=1, year=2013)
        end = datetime.date(month=12, day=1, year=2013)
        x = datetime.date(month=6, day=1, year=2013)
        is_in_range = date_in_range(start, end, x)
        self.assertTrue(is_in_range)

        start = datetime.date(month=1, day=1, year=2013)
        end = datetime.date(month=12, day=1, year=2013)
        x = datetime.date(month=6, day=1, year=2010)
        is_in_range = date_in_range(start, end, x)
        self.assertFalse(is_in_range)

    def test_parse_feed(self):
        feed_url = 'http://www.my.jobs/feed/rss'

        for use_json, count in [(True, 2), (False, 1)]:
            items = parse_feed(feed_url, use_json=use_json)

            # The second value in the items list is the total count from a
            # feed, which may not equal the number of items returned
            self.assertEqual(items[1], len(items[0]))
            item = items[0][0]
            for element in ['pubdate', 'title', 'description', 'link']:
                self.assertTrue(item[element])

    def test_parse_feed_with_count(self):
        feed_url = 'http://www.my.jobs/feed/rss'
        num_items = 1

        items, count = parse_feed(feed_url, num_items=num_items)
        self.assertEqual(count, num_items)

    def test_url_sort_options(self):
        feed = 'http://www.my.jobs/jobs/feed/rss?date_sort=False'

        # Test to make sure sort by "Relevance" has '&date_sort=False' added
        # a single time
        feed_url = url_sort_options(feed, "Relevance")
        parsed = urlparse(feed_url)
        query = parse_qs(parsed.query)
        self.assertEquals(parsed.path, "/jobs/feed/rss")
        self.assertEquals(query['date_sort'], [u'False'])
        # If a frequency isn't specified, days_ago should be missing from
        # the url.
        self.assertNotIn('days_ago', query)
    
        # Test to make sure sort by "Date" doesn't have anything added
        feed_url = url_sort_options(feed, "Date")
        self.assertEquals(feed_url, "http://www.my.jobs/jobs/feed/rss")

        # Test to make sure that passing in a frequency does in fact
        # add the frequency to the feed url.
        feed_url = url_sort_options(feed, "Relevance", frequency='D')
        query = parse_qs(urlparse(feed_url).query)
        self.assertEquals(query['days_ago'][0], '1')
        feed_url = url_sort_options(feed, "Relevance", frequency='W')
        query = parse_qs(urlparse(feed_url).query)
        self.assertEquals(query['days_ago'][0], '7')
        feed_url = url_sort_options(feed, "Relevance", frequency='M')
        query = parse_qs(urlparse(feed_url).query)
        self.assertEqual(query['days_ago'][0], '30')

    def test_unicode_in_search(self):
        search = SavedSearch(url=u"http://www.my.jobs/search?q=%E2%80%93",
                             user=self.user,
                             feed=u"http://www.my.jobs/search/feed/rss?q=%E2%80%93",
                             sort_by=u'Relevance')
        search.save()

        feed_url = url_sort_options(search.feed, search.sort_by)

        old = parse_qs(urlparse(search.feed).query)
        new = parse_qs(urlparse(feed_url).query)

        self.assertFalse(old.get('date_sort'))
        self.assertTrue(new['date_sort'][0])

        del new['date_sort']
        self.assertEqual(new, old)

    def test_feed_on_protected_site_no_access(self):
        from mydashboard.tests.factories import SeoSiteFactory
        site_id = settings.PROTECTED_SITES.keys()[0]
        site = SeoSiteFactory(pk=site_id, id=site_id)

        url = "http://%s?q=query" % site.domain
        result = update_url_if_protected(url, self.user)
        self.assertEqual(result, url)

    def test_feed_on_protected_site_with_access(self):
        from mydashboard.tests.factories import SeoSiteFactory
        site_id = settings.PROTECTED_SITES.keys()[0]
        site = SeoSiteFactory(pk=site_id, id=site_id)
        group_id = settings.PROTECTED_SITES.values()[0][0]
        Group.objects.create(pk=group_id, name='Test Group')

        self.user.groups.add(group_id)
        self.user.save()

        url = "http://%s?q=query" % site.domain
        expected_result = "%s&key=%s" % (url, settings.SEARCH_API_KEY)
        result = update_url_if_protected(url, self.user)
        self.assertEqual(result, expected_result)
示例#23
0
文件: models.py 项目: panyang/MyJobs
class MyProfileTests(TestCase):
    user_info = {
        'password1': 'complicated_password',
        'email': '*****@*****.**'
    }

    def setUp(self):
        super(MyProfileTests, self).setUp()
        self.user = UserFactory()

    def test_primary_name_save(self):
        """
        Saving a primary name when one already exists replaces it with
        the new primary name.
        """

        initial_name = PrimaryNameFactory(user=self.user)

        self.assertTrue(initial_name.primary)
        new_name = NewPrimaryNameFactory(user=self.user)
        initial_name = Name.objects.get(given_name='Alice')
        self.assertTrue(new_name.primary)
        self.assertFalse(initial_name.primary)

    def test_primary_name_save_multiuser(self):
        """
        Saving primary names when multiple users are present accurately
        sets and retrieves the correct name
        """
        self.user_2 = UserFactory(email='*****@*****.**')
        user_2_initial_name = PrimaryNameFactory(user=self.user_2)
        user_2_new_name = NewPrimaryNameFactory(user=self.user_2)

        initial_name = PrimaryNameFactory(user=self.user)
        new_name = NewPrimaryNameFactory(user=self.user)

        user_2_initial_name = Name.objects.get(given_name='Alice',
                                               user=self.user_2)
        user_2_new_name = Name.objects.get(given_name='Alicia',
                                           user=self.user_2)
        initial_name = Name.objects.get(given_name='Alice', user=self.user)

        self.assertTrue(new_name.primary)
        self.assertFalse(initial_name.primary)
        self.assertTrue(user_2_new_name.primary)
        self.assertFalse(user_2_initial_name.primary)

        with self.assertRaises(MultipleObjectsReturned):
            Name.objects.get(primary=True)
            Name.objects.get(primary=False)
            Name.objects.get(given_name='Alice')
            Name.objects.get(given_name='Alicia')
        Name.objects.get(primary=True, user=self.user_2)

    def test_email_activation_creation(self):
        """
        Creating a new secondary email creates a corresponding unactivated
        ActivationProfile.
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(email=secondary_email.email)
        self.assertEqual(secondary_email.email, activation.email)

    def test_send_activation(self):
        """
        The send_activation method in SecondaryEmail should send an
        activation link to the email address
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].to, [secondary_email.email])
        self.assertTrue('secondary email' in mail.outbox[0].body)

    def test_verify_email(self):
        """
        Clicking the activation link sets the ActivationProfile object to
        activated and sets the SecondaryEmail object to verified.
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        response = self.client.get(
            reverse('registration_activate', args=[activation.activation_key])
            + '?verify-email=%s' % self.user.email)
        secondary_email = SecondaryEmail.objects.get(
            user=self.user, email=secondary_email.email)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        self.assertEqual(response.status_code, 200)
        self.assertTrue(secondary_email.verified)

    def test_set_primary_email(self):
        """
        Calling the set_as_primary method in the SecondaryEmail removes it from
        SecondaryEmail, replaces the current address on the User model, and
        adds the replaced address to the SecondaryEmail table.

        """
        old_primary = self.user.email
        secondary_email = SecondaryEmailFactory(user=self.user)
        new_primary = secondary_email.email

        for email in [old_primary, new_primary]:
            # Emails must be verified to make them primary.
            activation = ActivationProfile.objects.get_or_create(
                user=self.user, email=email)[0]
            ActivationProfile.objects.activate_user(activation.activation_key)

        secondary_email = SecondaryEmail.objects.get(email=new_primary)
        secondary_email.set_as_primary()

        with self.assertRaises(SecondaryEmail.DoesNotExist):
            SecondaryEmail.objects.get(email=new_primary)
        old_email = SecondaryEmail.objects.get(email=old_primary)
        self.assertTrue(old_email.verified)
        user = User.objects.get(email=new_primary)

    def test_duplicate_same_primary_name(self):
        """
        Makes sure that one can not create duplicate primary names.
        """
        primary_name1 = PrimaryNameFactory(user=self.user)
        primary_name2 = PrimaryNameFactory(user=self.user)

        num_results = self.user.profileunits_set.filter(
            content_type__name='name').count()
        self.assertEqual(num_results, 1)

    def test_different_primary_name(self):
        primary_name1 = PrimaryNameFactory(user=self.user)
        primary_name2 = NewPrimaryNameFactory(user=self.user)

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 1)
        self.assertEqual(non_primary_name_count, 1)

    def test_non_primary_name_to_primary(self):
        name = NewNameFactory(user=self.user)
        primary_name1 = PrimaryNameFactory(user=self.user)

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 1)
        self.assertEqual(non_primary_name_count, 0)

    def test_primary_name_to_non_primary(self):
        primary_name = PrimaryNameFactory(user=self.user)
        primary_name.primary = False
        primary_name.save()

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 0)
        self.assertEqual(non_primary_name_count, 1)

    def test_duplicate_name(self):
        """
        Makes sure that duplicate names is not saving.
        """
        name1 = NewNameFactory(user=self.user)
        name2 = NewNameFactory(user=self.user)

        num_results = Name.objects.filter(user=self.user).count()
        self.assertEqual(num_results, 1)

    def test_unverified_primary_email(self):
        """
        Only verified emails can be set as the primary email
        """

        old_primary = self.user.email
        secondary_email = SecondaryEmailFactory(user=self.user)
        primary = secondary_email.set_as_primary()

        with self.assertRaises(SecondaryEmail.DoesNotExist):
            SecondaryEmail.objects.get(email=old_primary)
        self.assertFalse(primary)
        user = User.objects.get(email=old_primary)
        self.assertEqual(user.email, old_primary)

    def test_maintain_verification_state(self):
        """
        For security reasons, the state of verification of the user email
        should be the same as it is when it is transferred into SecondaryEmail
        """

        old_primary = self.user.email
        self.user.is_active = False
        self.user.save()
        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        ActivationProfile.objects.activate_user(activation.activation_key)
        secondary_email = SecondaryEmail.objects.get(
            user=self.user, email=secondary_email.email)
        new_primary = secondary_email.email
        secondary_email.set_as_primary()

        old_email = SecondaryEmail.objects.get(email=old_primary)
        self.assertFalse(old_email.verified)
        user = User.objects.get(email=new_primary)

    def test_same_secondary_email(self):
        """
        All emails are unique. If an email is used as a user's primary email or
        another secondary email, it may not be used as a secondary email again.
        """
        secondary_email = SecondaryEmailFactory(user=self.user)
        with self.assertRaises(IntegrityError):
            new_secondary_email = SecondaryEmailFactory(user=self.user)
        new_secondary_email = SecondaryEmailFactory(user=self.user,
                                                    email='*****@*****.**')

    def test_delete_secondary_email(self):
        """
        Deleting a secondary email should also delete its activation profile
        """
        self.assertEqual(ActivationProfile.objects.count(), 0)
        secondary_email = SecondaryEmailFactory(user=self.user)
        self.assertEqual(ActivationProfile.objects.count(), 1)
        secondary_email.delete()
        self.assertEqual(ActivationProfile.objects.count(), 0)

    def test_add_military_service(self):
        military_service = MilitaryServiceFactory(user=self.user)
        military_service.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="military service").count()
        self.assertEqual(ms_object, 1)

    def test_add_license(self):
        license_form = LicenseFactory(user=self.user)
        license_form.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="license").count()
        self.assertEqual(ms_object, 1)

    def test_add_website(self):
        website_instance = WebsiteFactory(user=self.user)
        website_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="website").count()
        self.assertEqual(ms_object, 1)

    def test_add_summary(self):
        summary_instance = SummaryFactory(user=self.user)
        summary_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="summary").count()
        self.assertEqual(ms_object, 1)

    def test_add_volunteer_history(self):
        vh_instance = VolunteerHistoryFactory(user=self.user)
        vh_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="volunteer history").count()
        self.assertEqual(ms_object, 1)
示例#24
0
class MyDashboardViewsTests(MyJobsBase):
    def setUp(self):
        super(MyDashboardViewsTests, self).setUp()
        group = Group.objects.get(name=CompanyUser.GROUP_NAME)
        self.user.groups.add(group)

        self.business_unit = BusinessUnitFactory()

        self.company.job_source_ids.add(self.business_unit)
        self.admin = CompanyUserFactory(user=self.user,
                                        company=self.company)
        self.microsite = SeoSiteFactory()
        self.microsite.business_units.add(self.business_unit)

        self.candidate_user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=self.candidate_user,
                           feed='http://test.jobs/jobs/feed/rss?',
                           url='http://test.jobs/search?q=django',
                           label='test Jobs')

        for i in range(5):
            # Create 5 new users
            user = UserFactory(email='*****@*****.**' % i)
            for search in SEARCH_OPTS:
                # Create 15 new searches and assign three per user
                SavedSearchFactory(user=user,
                                   url='http://test.jobs/search?q=%s' % search,
                                   feed='http://test.jobs/jobs/feed/rss?',
                                   label='%s Jobs' % search)
        update_solr_task(settings.TEST_SOLR_INSTANCE)

    def tearDown(self):
        super(MyDashboardViewsTests, self).tearDown()
        for location in settings.TEST_SOLR_INSTANCE.values():
            solr = pysolr.Solr(location)
            solr.delete(q='*:*')

    def add_analytics_data(self, type_, num_to_add=2):
        """
        Adds testing analytics data to Solr.

        Adds two entries per page category, one for unauthenticated and one for
        authenticated hits.
        """
        dicts = []
        base_dict = {
            'domain': self.microsite.domain,
            'view_date': datetime.now(),
            'company_id': self.company.pk,
        }
        home_dict = {
            'page_category': 'home'
        }
        view_dict = {
            'job_view_guid': '1'*32,
            'job_view_buid': self.business_unit.pk,
            'page_category': 'listing'
        }
        search_dict = {
            'page_category': 'results'
        }
        apply_dict = {
            'job_view_guid': '2'*32,
            'job_view_buid': self.business_unit.pk,
            'page_category': 'redirect'
        }

        if type_ == 'home':
            analytics_dict = home_dict
        elif type_ == 'listing':
            analytics_dict = view_dict
        elif type_ == 'results':
            analytics_dict = search_dict
        else:
            analytics_dict = apply_dict

        analytics_dict.update(base_dict)
        for _ in range(num_to_add):
            dicts.append(analytics_dict.copy())

        for analytics_dict in dicts:
            analytics_dict['aguid'] = uuid.uuid4().hex
            analytics_dict['uid'] = 'analytics##%s#%s' % (
                analytics_dict['view_date'],
                analytics_dict['aguid']
            )

        for location in settings.TEST_SOLR_INSTANCE.values():
            solr = pysolr.Solr(location)
            solr.add(dicts)

    @unittest.skip("Correct behavior undefined with respect to duplicates.")
    def test_number_of_searches_and_users_is_correct(self):
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))
        # 6 users total
        self.assertEqual(response.context['total_candidates'], 6)

        old_search = SavedSearch.objects.all()[0]
        old_search.created_on -= timedelta(days=31)
        old_search.save()

        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})

        self.assertEqual(response.context['total_candidates'], 6)

    def test_facets(self):
        education = EducationFactory(user=self.candidate_user)
        adr = AddressFactory(user=self.candidate_user)
        license = LicenseFactory(user=self.candidate_user)
        self.candidate_user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        base_url = 'http://testserver/candidates/view?company={company}'
        country_str = base_url + '&location={country}'
        education_str = base_url + '&education={education}'
        license_str = base_url + '&license={license_name}'

        country_str = country_str.format(
            company=self.company.pk, country=adr.country_code)
        education_str = education_str.format(
            company=self.company.pk, education=education.education_level_code)
        license_str = license_str.format(
            company=self.company.pk, license_name=license.license_name)

        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard')+q)
        soup = BeautifulSoup(response.content)

        types = ['Country', 'Education', 'License']
        hrefs = []
        for facet_type in types:
            container = soup.select('#%s-details-table' % facet_type)[0]
            href = container.select('a')[0].attrs['href']
            hrefs.append(href)

        self.assertIn(country_str, hrefs)
        self.assertIn(education_str, hrefs)
        self.assertIn(license_str, hrefs)

    def test_filters(self):
        adr = AddressFactory(user=self.candidate_user)
        self.candidate_user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        country_str = 'http://testserver/candidates/view?company={company}&amp;location={country}'
        country_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}"><span>&#10006;</span> {country_long}</a><br>'
        region_str = 'http://testserver/candidates/view?company={company}&amp;location={country}-{region}'
        region_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}&amp;location={country}"><span>&#10006;</span> {region}, {country}</a>'
        city_str = 'http://testserver/candidates/view?company={company}&amp;location={country}-{region}-{city}'
        city_filter_str = '<a class="applied-filter" href="http://testserver/candidates/view?company={company}&amp;location={country}-{region}"><span>&#10006;</span> {city}, {region}, {country}</a>'

        country_str = country_str.format(company=self.company.pk, country=adr.country_code)
        country_filter_str = country_filter_str.format(company=self.company.pk, country=adr.country_code,
                                                       country_long=country_codes[adr.country_code])
        region_str = region_str.format(company=self.company.pk, country=adr.country_code,
                                       region=adr.country_sub_division_code)
        region_filter_str = region_filter_str.format(company=self.company.pk, region=adr.country_sub_division_code,
                                                     country=adr.country_code,
                                                     country_long=country_codes[adr.country_code])
        city_str = city_str.format(company=self.company.pk, country=adr.country_code,
                                   region=adr.country_sub_division_code,
                                   city=adr.city_name)
        city_filter_str = city_filter_str.format(company=self.company.pk, country=adr.country_code,
                                                 region=adr.country_sub_division_code,
                                                 city=adr.city_name,
                                                 country_long=country_codes[adr.country_code])

        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(country_str, response.content)

        q = '?company={company}&location={country}'
        q = q.format(company=str(self.company.id), country=adr.country_code)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(country_filter_str, response.content)
        self.assertIn(region_str, response.content)

        q = '?company={company}&location={country}-{region}'
        q = q.format(company=str(self.company.id), country=adr.country_code,
                     region=adr.country_sub_division_code)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(region_filter_str, response.content)
        self.assertIn(city_str, response.content)

        q = '?company={company}&location={country}-{region}-{city}'
        q = q.format(company=str(self.company.id), country=adr.country_code,
                     region=adr.country_sub_division_code,
                     city=adr.city_name)
        response = self.client.post(reverse('dashboard')+q)
        self.assertIn(city_filter_str, response.content)

    @unittest.skip("Correct behavior undefined with respect to duplicates.")
    def test_search_field(self):
        # Build url
        def build_url(search):
            q = '?company={company}&search={search}'
            q = q.format(company=str(self.company.id), search=search)
            return reverse('dashboard') + q

        # assert it finds all 5 searches.
        response = self.client.post(build_url('python'))
        soup = BeautifulSoup(response.content)
        count_box = soup.select('.count-box-left')
        count = int(count_box[0].text)
        self.assertEqual(count, 5)

        # 6 users total
        response = self.client.post(build_url('example'))
        soup = BeautifulSoup(response.content)
        count_box = soup.select('.count-box-left')
        count = int(count_box[0].text)
        self.assertIn(count, [6, 7])

    def test_search_email(self):
        """We should be able to search for an exact email."""
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='*****@*****.**')
        url = reverse('dashboard') + q

        response = self.client.post(url)
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 1)

    def test_search_domain(self):
        """We should be able to search for domain."""
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        user.save()
        update_solr_task(settings.TEST_SOLR_INSTANCE)

        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='shouldWork.com')
        url = reverse('dashboard') + q

        response = self.client.post(url)
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 1)

    def test_search_updates_facet_counts(self):
        # Add ProfileData to the candidate_user
        EducationFactory(user=self.candidate_user)
        AddressFactory(user=self.candidate_user)
        LicenseFactory(user=self.candidate_user)
        self.candidate_user.save()

        # Create a new user with ProfileData
        user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=user,
                           url='http://test.jobs/search?q=python',
                           feed='http://test.jobs/jobs/feed/rss?',
                           label='Python Jobs')
        EducationFactory(user=user)
        AddressFactory(user=user)
        LicenseFactory(user=user)
        user.save()

        update_solr_task(settings.TEST_SOLR_INSTANCE)

        # Assert there are two users with country codes
        country_tag = '#Country-details-table .facet-count'
        q = '?company={company}'
        q = q.format(company=str(self.company.id))
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 2)

        # When we search, the facet count updates.
        q = '?company={company}&search={search}'
        q = q.format(company=str(self.company.id), search='find')
        response = self.client.post(reverse('dashboard') + q)
        soup = BeautifulSoup(response.content)
        self.assertEqual(int(soup.select(country_tag)[0].text), 1)

    # Tests to see if redirect from /candidates/ goes to candidates/view/
    def test_redirect_to_candidates_views_default_page(self):
        response = self.client.post('/candidates/')

        # response returns HttpResponsePermanentRedirect which returns a 301
        # status code instead of the normal 302 redirect status code
        self.assertRedirects(response, '/candidates/view/', status_code=301,
                             target_status_code=200)

        response = self.client.post(reverse('dashboard'))

        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content)
        company_name = soup.find('h1')
        company_name = company_name.next

        self.assertEqual(company_name, self.company.name)

    # Eventually these opted-in/out will be changed to
    # track if user is part of company's activity feed
    def test_candidate_has_opted_in(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 6)
        self.assertEqual(len(info), 16)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_with_activites(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 1)
        self.assertEqual(len(info), 3)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_and_activites(self):
        saved_search = SavedSearch.objects.get(user=self.candidate_user)
        saved_search.delete()
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'})

        self.assertFalse(info)
        self.assertEqual(response.status_code, 404)

    def test_export_csv(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=csv')
        self.assertTrue(response.content)
        self.assertEqual(response.status_code, 200)

    def test_export_xml(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=xml')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_export_json(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=json')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_dashboard_analytics_no_data(self):
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})

        soup = BeautifulSoup(response.content)

        for selector in ['#total-clicks',
                         '#total-home',
                         '#total-job-views',
                         '#total-search']:

            container = soup.select(selector)
            # Empty list means no elements were found.
            self.assertEqual(container, [])

    def test_dashboard_analytics_with_data(self):
        for type_ in ['home', 'listing', 'results']:
            self.add_analytics_data(type_)
        num_clicks = 1234
        self.add_analytics_data('redirect', num_to_add=num_clicks)

        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))

        soup = BeautifulSoup(response.content)

        for selector in ['#total-clicks',
                         '#total-home',
                         '#total-job-views',
                         '#total-search']:

            # This should be the parent container for all analytics data
            # of this type
            container = soup.select(selector)[0]

            # All hits, humanized
            all_hits = container.select('span')[0]
            if selector == '#total-clicks':
                expected = '1.2k'
            else:
                expected = '2'
            self.assertEqual(all_hits.text.strip(), expected)

            # All hits, raw number
            if selector == '#total-clicks':
                full = container.attrs['data-original-title']
                self.assertEqual(full.strip(),
                                 '1,234')
            else:
                with self.assertRaises(KeyError):
                    # This is marked as having no effect, which is intended
                    container.attrs['data-original-title']

    def test_dashboard_with_no_microsites(self):
        """
        Trying to access the dashboard of a company that has no microsites
        associated with it should not create malformed solr queries.
        """
        self.microsite.delete()
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id))
        self.assertEqual(response.status_code, 200)
示例#25
0
class MyProfileTests(MyJobsBase):
    user_info = {'password1': 'complicated_password',
                 'email': '*****@*****.**'}

    def setUp(self):
        super(MyProfileTests, self).setUp()
        self.user = UserFactory()

    def test_primary_name_save(self):
        """
        Saving a primary name when one already exists replaces it with
        the new primary name.
        """

        initial_name = PrimaryNameFactory(user=self.user)

        self.assertTrue(initial_name.primary)
        new_name = NewPrimaryNameFactory(user=self.user)
        initial_name = Name.objects.get(given_name='Alice')
        self.assertTrue(new_name.primary)
        self.assertFalse(initial_name.primary)

    def test_primary_name_save_multiuser(self):
        """
        Saving primary names when multiple users are present accurately
        sets and retrieves the correct name
        """
        self.user_2 = UserFactory(email='*****@*****.**')
        user_2_initial_name = PrimaryNameFactory(user=self.user_2)
        user_2_new_name = NewPrimaryNameFactory(user=self.user_2)

        initial_name = PrimaryNameFactory(user=self.user)
        new_name = NewPrimaryNameFactory(user=self.user)

        user_2_initial_name = Name.objects.get(given_name='Alice',
                                               user=self.user_2)
        user_2_new_name = Name.objects.get(given_name='Alicia',
                                           user=self.user_2)
        initial_name = Name.objects.get(given_name='Alice', user=self.user)

        self.assertTrue(new_name.primary)
        self.assertFalse(initial_name.primary)
        self.assertTrue(user_2_new_name.primary)
        self.assertFalse(user_2_initial_name.primary)

        with self.assertRaises(MultipleObjectsReturned):
            Name.objects.get(primary=True)
            Name.objects.get(primary=False)
            Name.objects.get(given_name='Alice')
            Name.objects.get(given_name='Alicia')
        Name.objects.get(primary=True, user=self.user_2)

    def test_email_activation_creation(self):
        """
        Creating a new secondary email creates a corresponding unactivated
        ActivationProfile.
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(email=secondary_email.email)
        self.assertEqual(secondary_email.email, activation.email)

    def test_send_activation(self):
        """
        The send_activation method in SecondaryEmail should send an
        activation link to the email address
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].to, [secondary_email.email])
        self.assertTrue('secondary email' in mail.outbox[0].body)

    def test_verify(self):
        """
        Clicking the activation link sets the ActivationProfile object to
        activated and sets the SecondaryEmail object to verified.
        """

        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        response = self.client.get(reverse('registration_activate',
                                           args=[activation.activation_key]) +
                                   '?verify=%s' % self.user.user_guid)
        secondary_email = SecondaryEmail.objects.get(user=self.user,
                                                     email=secondary_email.email)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        self.assertEqual(response.status_code, 200)
        self.assertTrue(secondary_email.verified)

    def test_set_primary_email(self):
        """
        Calling the set_as_primary method in the SecondaryEmail removes it from
        SecondaryEmail, replaces the current address on the User model, and
        adds the replaced address to the SecondaryEmail table.

        """
        old_primary = self.user.email
        secondary_email = SecondaryEmailFactory(user=self.user)
        new_primary = secondary_email.email

        for email in [old_primary, new_primary]:
            # Emails must be verified to make them primary.
            activation = ActivationProfile.objects.get_or_create(user=self.user,
                                                                 email=email)[0]
            ActivationProfile.objects.activate_user(activation.activation_key)

        secondary_email = SecondaryEmail.objects.get(email=new_primary)
        secondary_email.set_as_primary()

        with self.assertRaises(SecondaryEmail.DoesNotExist):
            SecondaryEmail.objects.get(email=new_primary)
        old_email = SecondaryEmail.objects.get(email=old_primary)
        self.assertTrue(old_email.verified)
        user = User.objects.get(email=new_primary)

    def test_duplicate_same_primary_name(self):
        """
        Makes sure that one can not create duplicate primary names.
        """
        primary_name1 = PrimaryNameFactory(user=self.user)
        primary_name2 = PrimaryNameFactory(user=self.user)

        num_results = self.user.profileunits_set.filter(
            content_type__name='name').count()
        self.assertEqual(num_results, 1)

    def test_different_primary_name(self):
        primary_name1 = PrimaryNameFactory(user=self.user)
        primary_name2 = NewPrimaryNameFactory(user=self.user)

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 1)
        self.assertEqual(non_primary_name_count, 1)

    def test_non_primary_name_to_primary(self):
        name = NewNameFactory(user=self.user)
        primary_name1 = PrimaryNameFactory(user=self.user)

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 1)
        self.assertEqual(non_primary_name_count, 0)

    def test_primary_name_to_non_primary(self):
        primary_name = PrimaryNameFactory(user=self.user)
        primary_name.primary = False
        primary_name.save()

        primary_name_count = Name.objects.filter(user=self.user,
                                                 primary=True).count()
        non_primary_name_count = Name.objects.filter(user=self.user,
                                                     primary=False).count()

        self.assertEqual(primary_name_count, 0)
        self.assertEqual(non_primary_name_count, 1)

    def test_duplicate_name(self):
        """
        Makes sure that duplicate names is not saving.
        """
        name1 = NewNameFactory(user=self.user)
        name2 = NewNameFactory(user=self.user)

        num_results = Name.objects.filter(user=self.user).count()
        self.assertEqual(num_results, 1)

    def test_unverified_primary_email(self):
        """
        Only verified emails can be set as the primary email
        """

        old_primary = self.user.email
        secondary_email = SecondaryEmailFactory(user=self.user)
        primary = secondary_email.set_as_primary()

        with self.assertRaises(SecondaryEmail.DoesNotExist):
            SecondaryEmail.objects.get(email=old_primary)
        self.assertFalse(primary)
        user = User.objects.get(email=old_primary)
        self.assertEqual(user.email, old_primary)

    def test_maintain_verification_state(self):
        """
        For security reasons, the state of verification of the user email
        should be the same as it is when it is transferred into SecondaryEmail
        """

        old_primary = self.user.email
        self.user.is_active = False
        self.user.save()
        secondary_email = SecondaryEmailFactory(user=self.user)
        activation = ActivationProfile.objects.get(user=self.user,
                                                   email=secondary_email.email)
        ActivationProfile.objects.activate_user(activation.activation_key)
        secondary_email = SecondaryEmail.objects.get(user=self.user,
                                                     email=secondary_email.email)
        new_primary = secondary_email.email
        secondary_email.set_as_primary()

        old_email = SecondaryEmail.objects.get(email=old_primary)
        self.assertFalse(old_email.verified)
        user = User.objects.get(email=new_primary)

    def test_same_secondary_email(self):
        """
        All emails are unique. If an email is used as a user's primary email or
        another secondary email, it may not be used as a secondary email again.
        """
        secondary_email = SecondaryEmailFactory(user=self.user)
        with transaction.atomic():
            with self.assertRaises(IntegrityError):
                new_secondary_email = SecondaryEmailFactory(user=self.user)
        new_secondary_email = SecondaryEmailFactory(user=self.user,
                                                    email='*****@*****.**')

    def test_delete_secondary_email(self):
        """
        Deleting a secondary email should also delete its activation profile
        """
        self.assertEqual(ActivationProfile.objects.count(), 0)
        secondary_email = SecondaryEmailFactory(user=self.user)
        self.assertEqual(ActivationProfile.objects.count(), 1)
        secondary_email.delete()
        self.assertEqual(ActivationProfile.objects.count(), 0)

    def test_add_military_service(self):
        military_service = MilitaryServiceFactory(user=self.user)
        military_service.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="military service").count()
        self.assertEqual(ms_object, 1)

    def test_add_license(self):
        license_form = LicenseFactory(user=self.user)
        license_form.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="license").count()
        self.assertEqual(ms_object, 1)

    def test_add_website(self):
        website_instance = WebsiteFactory(user=self.user)
        website_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="website").count()
        self.assertEqual(ms_object, 1)

    def test_add_summary(self):
        summary_instance = SummaryFactory(user=self.user)
        summary_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="summary").count()
        self.assertEqual(ms_object, 1)

    def test_add_volunteer_history(self):
        vh_instance = VolunteerHistoryFactory(user=self.user)
        vh_instance.save()

        ms_object = ProfileUnits.objects.filter(
            content_type__name="volunteer history").count()
        self.assertEqual(ms_object, 1)
示例#26
0
class MyJobsAdminTests(MyJobsBase):
    def setUp(self):
        super(MyJobsAdminTests, self).setUp()
        self.user.set_password('5UuYquA@')
        self.user.is_superuser = True
        self.user.save()
        self.account_owner = UserFactory(email='*****@*****.**')
        SeoSiteFactory(domain='secure.my.jobs')
        mail.outbox = []

        self.data = {'_selected_action': [unicode(self.account_owner.pk)],
                     'action': 'request_account_access'}

    def test_request_access_to_staff(self):
        """
        Requesting access to a staff/superuser account is not allowed.
        """
        self.account_owner.is_staff = True
        self.account_owner.save()

        # Selecting the action in the User changelist and pressing "OK" should
        # immediately show a notification at the top of the page.
        response = self.client.post(
            reverse('admin:myjobs_user_changelist'),
            self.data, follow=True)
        self.assertEqual(len(mail.outbox), 0)
        self.assertContains(response, ("Requesting access to staff or "
                                       "superusers is not supported."))

        # Manually constructing a post to the relevant url should redirect
        # to the User changelist and not send notification emails.
        response = self.client.post(
            reverse('request-account-access',
                    kwargs={'uid': self.account_owner.pk}),
            {'reason': 'reason here'})

        self.assertRedirects(response, reverse('admin:myjobs_user_changelist'))
        self.assertEqual(len(mail.outbox), 0)

    def test_request_access_to_non_staff(self):
        """
        Requesting access to a non-staff/superuser account succeeds if the
        target is not a staff/superuser account and the requesting staff
        member provides a reason.
        """
        # Request access to an account to get to the request form.
        response = self.client.post(
            reverse('admin:myjobs_user_changelist'),
            self.data, follow=True)
        self.assertContains(response, "What is the nature of this request?",
                            msg_prefix="Did not redirect to the request form")
        url = reverse('request-account-access',
                      kwargs={'uid': self.account_owner.pk})
        last_redirect = response.redirect_chain[-1][0]

        # If the admin action determines that it is valid, it redirects. Ensure
        # we redirected to the expected location.
        self.assertTrue(last_redirect.endswith(url),
                        msg="Did not redirect as expected")

        # Try submitting the request form without a reason.
        response = self.client.post(url)
        self.assertContains(response, "This field is required.",
                            msg_prefix=("Form error not present on invalid "
                                        "submission"))
        self.assertEqual(len(mail.outbox), 0,
                         msg="Mail sent despite form errors")

        # # Submit again, providing a reason.
        self.client.post(url, {'reason': 'reason here'})
        self.assertEqual(len(mail.outbox), 1,
                         msg="Mail did not send on successful form submission")
        email = mail.outbox[0]
        self.assertTrue(self.account_owner.email in email.to,
                        msg="Email was sent to the wrong user")
        self.assertTrue('reason here' in email.body,
                        msg="Account access reason was not in the sent email")

    def test_export_as_csv_admin_action(self):
        """
        Tests the ability to export the list of destination manipulations as a
        CSV.

        """
        email = '*****@*****.**'
        password = '******'
        UserFactory(
            email=email, password=password, is_staff=True, is_superuser=True)
        # only superusers are allowed to use Django amin
        self.client.login(username=email, password=password)

        manipulations = [DestinationManipulationFactory(view_source=i)
                         for i in range(200, 210)]
        # this is the format we expect results to be in if deserializing CSV
        # into a list of dicts
        formatted_manipulations = [{
            u'View Source': unicode(m.view_source),
            u'View Source Name': '',
            u'BUID': unicode(m.buid),
            u'Action Type': unicode(m.action_type),
            u'Value 1': unicode(m.value_1),
            u'Value 2': unicode(m.value_2),
            u'Action': unicode(m.action)
        } for m in manipulations]

        args = {
            'action': 'export_as_csv',
            '_selected_action': [
                unicode(m.pk) for m in manipulations[:5]
            ]
        }
        changelist_url = reverse(
            "admin:redirect_destinationmanipulation_changelist")

        # asking to export as csv when selected items should serialize only
        # those items
        response = self.client.post(changelist_url, args)
        reader = csv.DictReader(response.content.split('\r\n'))
        self.assertItemsEqual(list(reader), formatted_manipulations[:5])

        args['select_across'] = '1'

        # choosing "select all" should export all records in the queryset,
        # regardless of the list of selected items passed
        response = self.client.post(changelist_url, args)
        reader = csv.DictReader(response.content.split('\r\n'))
        self.assertItemsEqual(list(reader), formatted_manipulations)
示例#27
0
文件: views.py 项目: jpaezsa/MyJobs
class MyDashboardViewsTests(TestCase):
    def setUp(self):
        self.staff_user = UserFactory()
        group = Group.objects.get(name=CompanyUser.GROUP_NAME)
        self.staff_user.groups.add(group)
        self.staff_user.save()

        self.company = CompanyFactory()
        self.company.save()
        self.admin = CompanyUserFactory(user=self.staff_user,
                                        company=self.company)
        self.admin.save()
        self.microsite = MicrositeFactory(company=self.company)
        self.microsite.save()

        self.client = TestClient()
        self.client.login_user(self.staff_user)

        self.candidate_user = UserFactory(email="*****@*****.**")
        SavedSearchFactory(user=self.candidate_user,
                           url='http://test.jobs/search?q=django',
                           label='test Jobs')
        self.candidate_user.save()

        for i in range(5):
            # Create 5 new users
            user = UserFactory(email='*****@*****.**' % i)
            for search in SEARCH_OPTS:
                # Create 15 new searches and assign three per user
                SavedSearchFactory(user=user,
                                   url='http://test.jobs/search?q=%s' % search,
                                   label='%s Jobs' % search)

    def test_number_of_searches_and_users_is_correct(self):
        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})
        soup = BeautifulSoup(response.content)
        # 10 searches total, two rows per search
        self.assertEqual(len(soup.select('#row-link-table tr')), 20)

        old_search = SavedSearch.objects.all()[0]
        old_search.created_on -= timedelta(days=31)
        old_search.save()

        response = self.client.post(
            reverse('dashboard')+'?company='+str(self.company.id),
            {'microsite': 'test.jobs'})
        soup = BeautifulSoup(response.content)
        self.assertEqual(len(soup.select('#row-link-table tr')), 20)

    # Tests to see if redirect from /candidates/ goes to candidates/view/
    def test_redirect_to_candidates_views_default_page(self):
        response = self.client.post('/candidates/')

        # response returns HttpResponsePermanentRedirect which returns a 301
        # status code instead of the normal 302 redirect status code
        self.assertRedirects(response, '/candidates/view/', status_code=301,
                             target_status_code=200)

        response = self.client.post(reverse('dashboard'))

        self.assertEqual(response.status_code, 200)

        soup = BeautifulSoup(response.content)
        company_name = soup.find('h1')
        company_name = company_name.next

        self.assertEqual(company_name, self.company.name)

    # Eventually these opted-in/out will be changed to
    # track if user is part of company's activity feed
    def test_candidate_has_opted_in(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 6)
        self.assertEqual(len(info), 16)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_with_activites(self):
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'}).findAll(
            'a', {'class': 'accordion-toggle'})
        info = soup.find('div', {'id': 'candidate-content'}).findAll('li')

        self.assertEqual(len(titles), 1)
        self.assertEqual(len(info), 3)
        self.assertEqual(response.status_code, 200)

    def test_candidate_page_load_without_profileunits_and_activites(self):
        saved_search = SavedSearch.objects.get(user=self.candidate_user)
        saved_search.delete()
        response = self.client.post(
            reverse('candidate_information',
                    )+'?company='+str(self.company.id)+'&user='******'div', {'id': 'candidate-content'})

        self.assertFalse(info)
        self.assertEqual(response.status_code, 404)

    def test_export_csv(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=csv')
        self.assertTrue(response.content)
        self.assertEqual(response.status_code, 200)

    def test_export_pdf(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=pdf')
        self.assertTrue(response.content.index('PDF'))
        self.assertEqual(response.templates[0].name,
                         'mydashboard/export/candidate_listing.html')
        self.assertEqual(response.status_code, 200)

    def test_export_xml(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=xml')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)

    def test_export_json(self):
        response = self.client.post(
            reverse('export_candidates')+'?company=' +
            str(self.company.id)+'&ex-t=json')
        self.assertTrue(response.content.index('candidates'))
        self.assertEqual(response.status_code, 200)
示例#28
0
    def test_analytics_log_parsing(self):
        """
        Ensure that analytics logs are parsed and stored in solr correctly
        """
        company = CompanyFactory(id=1)
        business_unit = BusinessUnitFactory(id=1000)
        company.job_source_ids.add(business_unit)

        # match and no_match will be used later to ensure that the correct
        # number of documents were associated with a company or associated
        # with the default company
        match = Mock(
            wraps=lambda: self.assertEqual(doc['company_id'], company.pk))
        no_match = Mock(
            wraps=lambda: self.assertEqual(doc['company_id'], 999999))

        for log_type in ['analytics', 'redirect']:
            log = MockLog(log_type=log_type)
            parse_log([log], self.test_solr)

            solr = Solr()
            results = solr.search(q='uid:analytics*')

            # fake logs contain two lines - one human and one bot hit
            # If it is getting processed correctly, there should be only one
            # hit recorded
            self.assertEqual(results.hits, 1)
            multi_field = 'facets'
            if log_type == 'redirect':
                with self.assertRaises(KeyError):
                    results.docs[0][multi_field]
            else:
                self.assertEqual(len(results.docs[0][multi_field]), 2)
            for field in results.docs[0].keys():
                if field != multi_field:
                    self.assertTrue(type(results.docs[0][field] != list))
            uuid.UUID(results.docs[0]['aguid'])
            with self.assertRaises(KeyError):
                results.docs[0]['User_user_guid']

            for doc in results.docs:
                if doc['job_view_buid'] == business_unit.pk:
                    # If business units match, company ids should match
                    match()
                else:
                    # Business units don't match; company id should be set to
                    # the default company
                    no_match()

            solr.delete()
            user = UserFactory(email="*****@*****.**")
            user.user_guid = '1e5f7e122156483f98727366afe06e0b'
            user.save()
            parse_log([log], self.test_solr)
            results = solr.search(q='uid:analytics*')
            for guid in ['aguid', 'User_user_guid']:
                uuid.UUID(results.docs[0][guid])

            solr.delete()
            user.delete()

        # We have already determined that there are only two documents.
        # Ensure that there is exactly one document that matches a specific
        # company and one document that was given the default company
        self.assertEqual(match.call_count, 1)
        self.assertEqual(no_match.call_count, 1)
示例#29
0
class MySearchViewTests(MyJobsBase):
    def setUp(self):
        super(MySearchViewTests, self).setUp()
        self.client = TestClient()
        self.user = UserFactory()
        self.client.login_user(self.user)
        self.new_form_data = {
            'url': 'www.my.jobs/jobs',
            'feed': 'http://www.my.jobs/jobsfeed/rss?',
            'label': 'Jobs Label',
            'email': self.user.email,
            'frequency': 'D',
            'is_active': 'True',
            'jobs_per_email': 5,
            'sort_by': 'Relevance',
        }
        self.new_digest_data = {
            'is_active': 'True',
            'user': self.user,
            'email': self.user.email,
            'frequency': 'M',
            'day_of_month': 1,
        }
        self.new_form = forms.SavedSearchForm(user=self.user,
                                              data=self.new_form_data)

        self.patcher = patch('urllib2.urlopen', return_file())
        self.patcher.start()

    def tearDown(self):
        super(MySearchViewTests, self).tearDown()
        try:
            self.patcher.stop()
        except RuntimeError:
            # patcher was stopped in a test
            pass

    def test_search_main(self):
        response = self.client.get(reverse('saved_search_main'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'mysearches/saved_search_main.html')
        self.failUnless(isinstance(response.context['form'], forms.DigestForm))
        self.failUnless(isinstance(response.context['add_form'],
                                   forms.SavedSearchForm))

    def test_saved_search_digest_options(self):
        response = self.client.get(reverse('saved_search_main'))
        self.assertTrue('Digest Options' in response.content)
        self.assertFalse('digest-option' in response.content)

        self.assertTrue(self.new_form.is_valid())
        self.new_form.save()
        response = self.client.get(reverse('saved_search_main'))
        self.assertTrue('Digest Options' in response.content)
        self.assertTrue('digest-option' in response.content)

    def test_save_new_search_form(self):
        response = self.client.post(reverse('save_search_form'),
                                    data=self.new_form_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, '')

    def test_save_new_search_invalid(self):
        del self.new_form_data['frequency']
        response = self.client.post(reverse('save_search_form'),
                                    data=self.new_form_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(response.content).keys(),
                         ['frequency'])

    def test_get_edit_page(self):
        self.assertTrue(self.new_form.is_valid())
        self.new_form.save()
        search_id = self.new_form.instance.id
        response = self.client.get(
            reverse('edit_search')+'?id=%s' % search_id)
        self.assertEqual(response.status_code, 200)

        self.assertEqual(self.new_form.instance,
                         response.context['form'].instance)
        self.assertTemplateUsed(response, 'mysearches/saved_search_edit.html')

        search_id += 1
        response = self.client.get(
            reverse('edit_search')+'?id=%s' % search_id)
        self.assertEqual(response.status_code, 404)

    def test_save_edit_form(self):
        self.assertTrue(self.new_form.is_valid())
        self.new_form.save()
        search_id = self.new_form.instance.id

        self.new_form_data['frequency'] = 'W'
        self.new_form_data['day_of_week'] = 1
        self.new_form_data['url'] = 'www.my.jobs/search?'
        self.new_form_data['search_id'] = search_id

        new_form = forms.SavedSearchForm(user=self.user,
                                         data=self.new_form_data)
        response = self.client.post(reverse('save_search_form'),
                                    data=self.new_form_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, '')

        del self.new_form_data['frequency']

        response = self.client.post(reverse('save_search_form'),
                                    data=self.new_form_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(response.content).keys(), ['frequency'])

    def test_validate_url(self):
        response = self.client.post(reverse('validate_url'),
                                    data={'url': self.new_form_data['url']},
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        data = {u'rss_url': u'http://www.my.jobs/jobs/feed/rss',
                u'feed_title': u'My.jobs - Jobs',
                u'url_status': u'valid'}

        content = json.loads(response.content)
        self.assertEqual(content['rss_url'], data['rss_url'])
        self.assertEqual(content['url_status'], data['url_status'])

        response = self.client.post(reverse('validate_url'),
                                    data={'url': 'google.com'},
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(json.loads(response.content),
                         {'url_status': 'not valid'})

    def test_save_digest_form(self):
        response = self.client.post(reverse('save_digest_form'),
                                    self.new_digest_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content, '')

        del self.new_digest_data['email']
        response = self.client.post(reverse('save_digest_form'),
                                    self.new_digest_data,
                                    HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.content,
                         '{"email": ["This field is required."]}')

    def test_unsubscribe_owned_search(self):
        """
        Unsubscribing an owned saved search should result in
        that search being deactivated
        """
        search = SavedSearchFactory(user=self.user)
        self.assertTrue(search.is_active)

        response = self.client.get(reverse('unsubscribe')+'?id=%s' % search.id)
        search = models.SavedSearch.objects.get(id=search.id)
        self.assertFalse(search.is_active)
        self.assertTemplateUsed(response,
                                'mysearches/saved_search_disable.html')

    def test_unsubscribe_unowned_search(self):
        """
        Attempting to unsubscribe using a search that isn't yours
        should result in nothing happening to the search
        """
        user = UserFactory(email='*****@*****.**')
        search = SavedSearchFactory(user=user)

        response = self.client.get(reverse('unsubscribe')+'?id=%s' % search.id)
        search = models.SavedSearch.objects.get(id=search.id)
        self.assertTrue(search.is_active)
        self.assertEqual(response.status_code, 404)

    def test_unsubscribe_digest(self):
        """
        Unsubscribing a saved search digest should result in all
        of the owner's saved searches being disabled
        """
        digest = SavedSearchDigestFactory(user=self.user)
        searches = []
        for url in ['www.my.jobs/search?q=python', 'jobs.jobs/search?q=django']:
            searches.append(SavedSearchFactory(url=url, user=self.user))

        for search in searches:
            self.assertTrue(search.is_active)

        response = self.client.get(reverse('unsubscribe')+'?id=digest')
        searches = list(models.SavedSearch.objects.all())
        for search in searches:
            self.assertFalse(search.is_active)
        self.assertTemplateUsed(response,
                                'mysearches/saved_search_disable.html')
        self.assertEqual(response.status_code, 200)

    def test_anonymous_unsubscribe(self):
        search = SavedSearchFactory(user=self.user)
        Session.objects.all().delete()

        # Navigating to the 'unsubscribe' page while logged out...
        response = self.client.get(
            reverse('unsubscribe')+'?id='+str(search.id))
        path = response.request.get('PATH_INFO') + "?id=" + str(search.id)
        self.assertRedirects(response, reverse('home')+'?next='+path)
        # or with the wrong email address...
        response = self.client.get(
            reverse('unsubscribe') + '?id='+str(
                search.id)+'&[email protected]')
        # results in being redirected to the login page and the searches
        # remaining unchanged
        self.assertRedirects(response, reverse('home'))
        search = models.SavedSearch.objects.get(id=search.id)
        self.assertTrue(search.is_active)

        response = self.client.get(
            reverse('unsubscribe') + '?id=%s&verify=%s' % (
                search.id, self.user.user_guid))
        search = models.SavedSearch.objects.get(id=search.id)
        self.assertFalse(search.is_active)

    def test_delete_owned_search(self):
        search = SavedSearchFactory(user=self.user)
        self.assertEqual(models.SavedSearch.objects.count(), 1)

        response = self.client.get(
            reverse('delete_saved_search')+'?id=%s' % search.id)
        self.assertEqual(models.SavedSearch.objects.count(), 0)
        self.assertRedirects(response, reverse(
            'saved_search_main_query')+'?d='+str(urllib2.quote(
                                                 search.label)))

    def test_delete_all_searches(self):
        """
        Deleting all searches should only remove regular saved searches if the
        partner saved searches weren't created by the user trying to use it.
        """
        
        user = UserFactory(email='*****@*****.**')
        company = CompanyFactory(id=2423, name="Bacon Factory",
                                 user_created=False)
        SavedSearchFactory(user=self.user)
        pss = PartnerSavedSearchFactory(user=self.user, created_by=user,
                                        provider=company)

        response = self.client.get(reverse('delete_saved_search') +
            '?id=ALL')
        
        self.assertEqual(response.status_code, 302)
        # partner saved search should still exist...
        self.assertTrue(models.PartnerSavedSearch.objects.filter(
            pk=pss.pk).exists())
        # ... but the regular saved search shouldn't
        self.assertFalse(models.SavedSearch.objects.filter(
            partnersavedsearch__isnull=True).exists())

    def test_delete_unowned_search(self):
        """
        Attempting to delete a search that isn't yours should
        result in nothing happening to the search
        """
        user = UserFactory(email='*****@*****.**')
        search = SavedSearchFactory(user=user)

        response = self.client.get(
            reverse('delete_saved_search') + '?id=%s' % search.id)
        self.assertEqual(models.SavedSearch.objects.count(), 1)
        self.assertEqual(response.status_code, 404)

    def test_delete_owned_searches_by_digest(self):
        """
        Deleting with a saved search digest should result in
        all of the user's saved searches being deleted
        """
        digest = SavedSearchDigestFactory(user=self.user)
        searches = []
        for url in ['www.my.jobs/search?q=python', 'jobs.jobs/search?q=django']:
            searches.append(SavedSearchFactory(url=url, user=self.user))

        self.assertEqual(models.SavedSearch.objects.count(), 2)

        response = self.client.get(reverse(
            'delete_saved_search') + '?id=digest')
        self.assertEqual(models.SavedSearch.objects.count(), 0)
        self.assertRedirects(response, reverse(
            'saved_search_main_query') + '?d=all')

    def test_anonymous_delete_searches(self):
        search = SavedSearchFactory(user=self.user)
        Session.objects.all().delete()

        # Navigating to the 'delete saved search' page while logged out...
        response = self.client.get(
            reverse('delete_saved_search') + '?id=' + str(search.id))
        path = response.request.get('PATH_INFO') + "?id=" + str(search.id)
        self.assertRedirects(response, reverse('home') + '?next=' + path)
        self.assertEqual(models.SavedSearch.objects.count(), 1)
        # or with the wrong email address...
        response = self.client.get(
            reverse('delete_saved_search') + '?id=' + str(
                search.id) + '&[email protected]')
        # results in being redirected to the login page and no searches being
        # deleted
        self.assertRedirects(response, reverse('home'))
        self.assertEqual(models.SavedSearch.objects.count(), 1)

        response = self.client.get(
            reverse('delete_saved_search') + '?id=%s&verify=%s' % (
                search.id, self.user.user_guid))
        self.assertEqual(models.SavedSearch.objects.count(), 0)

        # assertRedirects follows any redirect and waits for a 200 status code;
        # anonymous users will always redirect, never returning a 200.
        self.client.login_user(self.user)
        self.assertRedirects(response, reverse(
            'saved_search_main_query') + '?d=' + str(urllib2.quote(
                search.label)))

    def test_widget_with_saved_search(self):
        search = SavedSearchFactory(user=self.user)
        response = self.client.get(reverse('saved_search_widget') +
                                   '?url=%s&callback=callback' % (
                                       search.url, ))
        edit_url = '\\"https://secure.my.jobs%s?id=%s\\"' % (
            reverse('edit_search'), search.pk)
        self.assertTrue(edit_url in response.content)

    def test_widget_with_partner_saved_search(self):
        company = CompanyFactory()
        partner = PartnerFactory(owner=company)
        ContactFactory(user=self.user, partner=partner)
        search = PartnerSavedSearchFactory(user=self.user,
                                           created_by=self.user,
                                           provider=company,
                                           partner=partner)

        response = self.client.get(reverse('saved_search_widget') +
                                   '?url=%s&callback=callback' % (
                                       search.url, ))
        edit_url = '\\"https://secure.my.jobs%s?id=%s&pss=True\\"' % (
            reverse('edit_search'), search.pk)
        self.assertTrue(edit_url in response.content)

    def test_viewing_feed_on_bad_search(self):
        search = SavedSearchFactory(user=self.user, url='http://404.com',
                                    feed='http://404.com/feed/json')
        response = self.client.get(reverse(
            'view_full_feed') + '?id=%s' % search.id)
        self.assertIn('The domain for this saved search is no longer valid.',
                      response.content)

    def test_send_link_appearance(self):
        """
        The button to manually send a saved search should not be displayed
        when DEBUG=False. If the url is guessed, nothing bad should happen.
        """
        self.user.is_superuser = True
        self.user.save()
        saved_search = SavedSearchFactory(user=self.user)
        partner_search = PartnerSavedSearchFactory(user=self.user,
                                                   created_by=self.user)
        ContactFactory(partner=partner_search.partner, user=self.user)

        for search in [saved_search, partner_search]:
            full_feed = reverse('view_full_feed') + '?id=%s' % search.id
            send_url = reverse('send_saved_search') + '?id=%s' % search.id
            if hasattr(search, 'partnersavedsearch'):
                send_url += '&is_pss=True'

            self.client.login_user(self.user)
            response = self.client.get(full_feed)
            self.assertNotIn('>Send</a>', response.content)
            send = self.client.get(send_url)
            self.assertEqual(send.status_code, 404)
            self.assertEqual(len(mail.outbox), 0)

            settings.DEBUG = True
            self.client.login_user(self.user)
            response = self.client.get(full_feed)
            self.assertIn('>Send</a>', response.content)
            send = self.client.get(send_url)
            self.assertEqual(send.status_code, 302)
            self.assertEqual(len(mail.outbox), 1)
            mail.outbox = []

            settings.DEBUG = False

    def test_send_link_respects_permissions(self):
        # The send_saved_search view requires that DEBUG be enabled.
        settings.DEBUG = True
        self.user.is_superuser = True
        self.user.save()
        search = SavedSearchFactory(user=self.user)
        search_2 = SavedSearchFactory(user=UserFactory(email='*****@*****.**'))
        send_url = reverse('send_saved_search') + '?id=%s'

        self.assertEqual(len(mail.outbox), 0)
        response = self.client.get(send_url % search.pk)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(len(mail.outbox), 1)
        response = self.client.get(send_url % search_2.pk)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(len(mail.outbox), 2)
        settings.DEBUG = False
示例#30
0
class PartnerSavedSearchTests(MyJobsBase):
    def setUp(self):
        super(PartnerSavedSearchTests, self).setUp()
        self.user = UserFactory()
        self.digest = SavedSearchDigestFactory(user=self.user)
        self.company = CompanyFactory()
        self.partner = PartnerFactory(owner=self.company)
        self.contact = ContactFactory(user=self.user,
                                      partner=self.partner)
        self.partner_search = PartnerSavedSearchFactory(user=self.user,
                                                        created_by=self.user,
                                                        provider=self.company,
                                                        partner=self.partner)
        # Partner searches are normally created with a form, which creates
        # invitations as a side effect. We're not testing the form, so we
        # can fake an invitation here.
        Invitation(invitee_email=self.partner_search.email,
                   invitee=self.partner_search.user,
                   inviting_user=self.partner_search.created_by,
                   inviting_company=self.partner_search.partner.owner,
                   added_saved_search=self.partner_search).save()

        self.patcher = patch('urllib2.urlopen', return_file())
        self.mock_urlopen = self.patcher.start()
        self.num_occurrences = lambda text, search_str: [match.start()
                                                         for match
                                                         in re.finditer(
                                                             search_str, text)]
        # classes and ids may get stripped out when pynliner inlines css.
        # all jobs contain a default (blank) icon, so we can search for that if
        # we want a job count
        self.job_icon = 'http://png.nlx.org/100x50/logo.gif'

    def tearDown(self):
        super(PartnerSavedSearchTests, self).tearDown()
        try:
            self.patcher.stop()
        except RuntimeError:
            # patcher was stopped in a test
            pass

    def test_send_partner_saved_search_as_saved_search(self):
        """
        When we send saved searches, we assume they are instances of SavedSearch
        and disregard any subclasses. Ensure that partner saved searches are
        correctly recorded as sent when this happens.
        """
        search = SavedSearch.objects.get(pk=self.partner_search.pk)
        mail.outbox = []
        self.assertEqual(ContactRecord.objects.count(), 1)
        self.partner_search.send_email()
        self.assertEqual(SavedSearchLog.objects.count(), 2)
        self.assertEqual(ContactRecord.objects.count(), 2)
        partner_record = ContactRecord.objects.all()[1]
        partner_email = mail.outbox.pop()

        search.send_email()
        self.assertEqual(SavedSearchLog.objects.count(), 3)
        self.assertEqual(ContactRecord.objects.count(), 3)
        search_record = ContactRecord.objects.all()[2]
        search_email = mail.outbox.pop()

        self.assertEqual(partner_record.notes, search_record.notes)
        self.assertEqual(partner_email.body, search_email.body)
        self.assertEqual(partner_record.notes, partner_email.body)
        self.assertFalse("Your resume is %s%% complete" %
                         self.user.profile_completion in partner_email.body)
        logs = SavedSearchLog.objects.all()[1:]
        for log in logs:
            self.assertTrue(log.was_sent)
            self.assertIsNotNone(log.contact_record)
        # These are separate contact records (different pks), but the notes
        # attached to each are identical.
        self.assertEqual(logs[0].contact_record.notes,
                         logs[1].contact_record.notes)

    def test_send_partner_saved_search_in_digest(self):
        """
        Saved search digests bypass the SavedSearch.send_email method. Ensure
        that partner saved searches are recorded when sent in a digest.
        """
        SavedSearchFactory(user=self.user)
        self.assertEqual(ContactRecord.objects.count(), 1)
        self.digest.send_email()
        self.assertEqual(SavedSearchLog.objects.count(), 2)
        self.assertEqual(ContactRecord.objects.count(), 2)
        email = mail.outbox[0]
        self.assertFalse("Your resume is %s%% complete" %
                         self.user.profile_completion in email.body)
        log = SavedSearchLog.objects.last()
        self.assertTrue(log.was_sent)

    def test_send_partner_saved_search_with_inactive_user(self):
        self.user.is_active = False
        self.user.save()
        mail.outbox = []
        self.partner_search.initial_email()
        email = mail.outbox.pop()
        self.assertTrue('Your account is not currently active.' in email.body)

        verify_url = get_activation_link(self.user)
        profile = ActivationProfile.objects.get(user=self.user,
                                                email=self.user.email)
        self.assertTrue(profile.activation_key in verify_url)
        self.assertTrue(self.user.user_guid in verify_url)
        self.assertTrue('https://secure.my.jobs%s' % verify_url
                        in email.body)

    def test_contact_record_created_by(self):
        ContactRecord.objects.all().delete()
        self.partner_search.initial_email()
        record = ContactRecord.objects.get()
        self.assertEqual(record.created_by, self.partner_search.created_by)

    def test_num_occurrences_instance_method(self):
        # quick sanity checks; searching for a string that doesn't exist
        # returns an empty list
        not_found = self.num_occurrences(
            'this is not the string you are looking for',
            self.job_icon)
        self.assertEqual(not_found, [])
        # searching for a string that does exist returns all starting indices
        # for the string
        found = self.num_occurrences(self.job_icon, self.job_icon)
        self.assertEqual(found, [0])

    def test_partner_saved_search_pads_results(self):
        """
        If a partner saved search results in less than the desired number of
        results, it should be padded with additional older results.
        """

        self.partner_search.send_email()
        partner_search_email = mail.outbox.pop()
        job_count = self.num_occurrences(partner_search_email.body,
                                         self.job_icon)
        self.assertEqual(len(job_count), 2)
        log = SavedSearchLog.objects.last()
        self.assertEqual(log.new_jobs, 1)
        self.assertEqual(log.backfill_jobs, 1)

    def test_saved_search_new_job_indicator(self):
        """
        Partner saved searches should include indicators for unseen jobs, while
        job seeker saved searches should not.
        """
        new_job_indicator = '>New! <'
        search = SavedSearchFactory(user=self.user)
        search.send_email()
        search_email = mail.outbox.pop()
        new_jobs = self.num_occurrences(search_email.body,
                                        new_job_indicator)
        self.assertEqual(len(new_jobs), 0)

        self.partner_search.send_email()
        partner_search_email = mail.outbox.pop()
        new_jobs = self.num_occurrences(partner_search_email.body,
                                        new_job_indicator)
        self.assertEqual(len(new_jobs), 1)

    def test_partner_saved_search_no_jobs(self):
        self.partner_search.feed = 'http://google.com'
        self.partner_search.save()
        self.partner_search.send_email()

        email = mail.outbox.pop()
        self.assertIn('There are no results for today!', email.body)

        # Confirm last_sent was updated even though there were no jobs.
        updated_search = SavedSearch.objects.get(pk=self.partner_search.pk)
        new_last_sent = updated_search.last_sent.replace(tzinfo=None)
        self.assertNotEqual(self.partner_search.last_sent, new_last_sent)

    def test_partner_saved_search_digest_no_jobs(self):
        self.digest.is_active = True
        self.digest.save()

        self.partner_search.feed = 'http://google.com'
        self.partner_search.save()
        self.partner_search.send_email()

        for x in range(1, 5):
            PartnerSavedSearchFactory(user=self.user, created_by=self.user,
                                      provider=self.company,
                                      feed='http://google.com',
                                      partner=self.partner)

        self.digest.send_email()

        email = mail.outbox.pop()
        self.assertEqual(email.body.count('There are no results for today!'), 5)

        # Confirm last_sent was updated on all searches even though there were
        # no jobs.
        kwargs = {
            'user': self.user,
            'last_sent__isnull': True,
        }
        self.assertEqual(SavedSearch.objects.filter(**kwargs).count(), 0)
示例#31
0
class MyJobsViewsTests(MyJobsBase):
    def setUp(self):
        super(MyJobsViewsTests, self).setUp()
        self.user = UserFactory()
        self.client = TestClient()
        self.client.login_user(self.user)
        self.events = ['open', 'delivered', 'click']

        self.email_user = UserFactory(email='*****@*****.**')

        self.auth = '%s:%s' % (settings.SENDGRID_BATCH_POST_USER,
                               settings.SENDGRID_BATCH_POST_PASSWORD)
        self.auth = base64.b64encode(self.auth)

    def make_messages(self, when, apiversion=2, categories=None):
        """
        Creates test api messages for sendgrid tests.

        Inputs:
        :self:  the calling object
        :when:  timestamp
        :apiversion: the version of the API to mimic
        :category: list of categories that the originating email was sent with;
            Optional

        Returns:
        JSON-esque object if apiversion<3
        JSON object is apiversion >=3

        """
        message = '{{"email":"*****@*****.**","timestamp":"{0}",' \
            '"event":"{1}"{2}}}'
        messages = []
        category = ''
        if categories:
            categories = ['"%s"' % cat for cat in categories]
            if len(categories) > 1:
                category = ',"category":[%s]' % ','.join(categories)
            else:
                category = ',"category":%s' % categories[0]
        for event in self.events:
            messages.append(message.format(time.mktime(when.timetuple()),
                                           event, category))
        if apiversion < 3:
            return '\r\n'.join(messages)
        else:
            return_json = ','.join(messages)
            return '['+return_json+']'

    def test_change_password_success(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': '7dY=Ybtk',
                                      'new_password2': '7dY=Ybtk'},
                                follow=True)
        user = User.objects.get(id=self.user.id)
        self.assertEqual(resp.status_code, 200)
        self.assertTrue(user.check_password('7dY=Ybtk'))

    def test_change_password_failure(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': '7dY=Ybtk',
                                      'new_password2': 'notNew'}, follow=True)

        errors = {'new_password2': [u'The new password fields did not match.'],
                  'new_password1': [u'The new password fields did not match.']}

        response_errors = resp.context['password_form'].errors
        self.assertItemsEqual(response_errors, errors)

    def test_password_without_lowercase_failure(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': 'SECRET',
                                      'new_password2': 'SECRET'}, follow=True)

        errors = {'new_password1': [
            u'Invalid Length (Must be 8 characters or more)',
            u'Based on a common sequence of characters',
            u'Must be more complex (Must contain 1 or more lowercase '
            u'characters)']}

        response_errors = resp.context['password_form'].errors
        self.assertItemsEqual(response_errors, errors)

    def test_password_without_uppercase_failure(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': 'secret',
                                      'new_password2': 'secret'}, follow=True)

        errors = {'new_password1': [
            u'Invalid Length (Must be 8 characters or more)',
            u'Based on a common sequence of characters',
            u'Must be more complex (Must contain 1 or more uppercase '
            u'characers)']}

        response_errors = resp.context['password_form'].errors
        self.assertItemsEqual(response_errors, errors)

    def test_password_without_digit_failure(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': 'Secret',
                                      'new_password2': 'Secret'}, follow=True)

        errors = {'new_password1': [
            u'Invalid Length (Must be 8 characters or more)',
            u'Based on a common sequence of characters',
            u'Must be more complex (Must contain 1 or more digits)']}

        response_errors = resp.context['password_form'].errors
        self.assertItemsEqual(response_errors, errors)

    def test_password_without_punctuation_failure(self):
        resp = self.client.post(reverse('edit_account')+'?password',
                                data={'password': '******',
                                      'new_password1': 'S3cr37',
                                      'new_password2': 'S3cr37'}, follow=True)

        errors = {'new_password1': [
            u'Invalid Length (Must be 8 characters or more)',
            u'Based on a common sequence of characters',
            u'Must be more complex (Must contain 1 or more punctuation '
            u'character)']}

        response_errors = resp.context['password_form'].errors
        self.assertItemsEqual(response_errors, errors)

    def test_partial_successful_profile_form(self):
        resp = self.client.post(reverse('home'),
                                data={'name-given_name': 'Alice',
                                      'name-family_name': 'Smith',
                                      'name-primary': False,
                                      'action': 'save_profile'}, follow=True)
        self.assertEquals(resp.content, 'valid')

    def test_complete_successful_profile_form(self):
        # Form with only some sections completely filled out should
        # save successfully

        resp = self.client.post(
            reverse('home'),
            data={'name-given_name': 'Alice',
                  'name-family_name': 'Smith',
                  'edu-organization_name': 'Stanford University',
                  'edu-degree_date': '2012-01-01',
                  'edu-education_level_code': '6',
                  'edu-degree_major': 'Basket Weaving',
                  'work-position_title': 'Rocket Scientist',
                  'work-organization_name': 'Blamco Inc.',
                  'work-start_date': '2013-01-01',
                  'ph-use_code': 'Home',
                  'ph-area_dialing': '999',
                  'ph-number': '1234567',
                  'addr-address_line_one': '123 Easy St.',
                  'addr-city_name': 'Pleasantville',
                  'addr-country_sub_division_code': 'IN',
                  'addr-country_code': 'USA',
                  'addr-postal_code': '99999',
                  'action': 'save_profile'},
            follow=True)

        self.assertEquals(resp.content, 'valid')

    def test_incomplete_profile_form(self):
        # Form with incomplete sections should return a page with "This field
        # "is required" errors
        resp = self.client.post(reverse('home'),
                                data={'name-given_name': 'Alice',
                                      'action': 'save_profile'}, follow=True)

        self.failIf(resp.context['name_form'].is_valid())
        self.assertContains(resp, 'This field is required.')

    def test_no_profile_duplicates(self):
        # An initial registration form with errors should save those parts
        # that are valid.
        self.client.post(reverse('home'),
                         data={'name-given_name': 'Alice',
                               'name-family_name': 'Smith',
                               'name-primary': False,
                               'education-organization_name': 'U',
                               'action': 'save_profile'}, follow=True)

        self.assertEqual(Name.objects.count(), 1)
        self.assertEqual(Education.objects.count(), 0)
        self.client.post(reverse('home'),
                         data={'name-given_name': 'Alice',
                               'name-family_name': 'Smith',
                               'name-primary': False,
                               'edu-organization_name': 'U',
                               'edu-degree_date': '2012-01-01',
                               'edu-education_level_code': 6,
                               'edu-degree_major': 'Basket Weaving',
                               'action': 'save_profile'}, follow=True)
        self.assertEqual(Name.objects.count(), 1)
        self.assertEqual(Education.objects.count(), 1)

    def test_delete_account(self):
        """
        Going to the delete_account view removes a user and their data
        completely
        """
        self.assertEqual(User.objects.count(), 2)
        self.client.get(reverse('delete_account'), follow=True)
        self.assertEqual(User.objects.count(), 1)

    def test_disable_account(self):
        """
        Going to the disabled account view disables the account, meaning that
        (1) a new activation key is created, (2) User is set to not active and
        (3) User is set to disabled.
        """

        custom_signals.create_activation_profile(sender=self, user=self.user,
                                                 email=self.user.email)
        profile = ActivationProfile.objects.get(user=self.user)
        ActivationProfile.objects.activate_user(profile.activation_key)
        profile = ActivationProfile.objects.get(user=self.user)
        self.assertEqual(profile.activation_key, 'ALREADY ACTIVATED')

        self.client.get(reverse('disable_account'), follow=True)
        user = User.objects.get(id=self.user.id)
        profile = ActivationProfile.objects.get(user=user)
        self.assertNotEqual(profile.activation_key, 'ALREADY ACTIVATED')
        self.assertTrue(user.is_disabled)

    def test_about_template(self):
        # About page should return a status code of 200
        response = self.client.get(reverse('about'))

        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'about.html')

    def test_batch_recent_message_digest(self):
        """
        Posting data created recently should result in one EmailLog instance
        being created per message and no emails being sent

        This test is for sendgrid APIs prior to version 3.

        """

        # Create activation profile for user; Used when disabling an account
        custom_signals.create_activation_profile(sender=self,
                                                 user=self.user,
                                                 email=self.user.email)

        now = date.today()

        # Submit a batch of three events created recently
        messages = self.make_messages(now, 2)
        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 3)
        process_batch_events()
        self.assertEqual(len(mail.outbox), 0)

        for log in EmailLog.objects.all():
            self.assertTrue(log.event in self.events)

    def test_batch_recent_message_digest_api_version_3(self):
        """
        Posting data created recently should result in one EmailLog instance
        being created per message and no emails being sent

        This test is for version 3 of the sendgrid API.

        """

        # Create activation profile for user; Used when disabling an account
        custom_signals.create_activation_profile(sender=self,
                                                 user=self.user,
                                                 email=self.user.email)

        now = date.today()

        # Submit a batch of three events created recently
        messages = self.make_messages(now, 3)
        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 3)
        process_batch_events()
        self.assertEqual(len(mail.outbox), 0)

        for log in EmailLog.objects.all():
            self.assertTrue(log.event in self.events)

    def test_batch_with_one_event(self):
        """
        Version 1 and Version 2 posts that contain a single event are valid
        JSON and do not play well with our batch digest method.

        This tests both forms of post to ensure they work.
        """
        now = date.today()

        # make_messages makes len(self.events) messages. We only want one
        self.events = ['open']
        for api_ver in [2, 3]:
            messages = self.make_messages(now, api_ver)
            response = self.client.post(reverse('batch_message_digest'),
                                        data=messages,
                                        content_type='text/json',
                                        HTTP_AUTHORIZATION='BASIC %s' %
                                                           self.auth)
            self.assertEqual(response.status_code, 200)
        process_batch_events()
        self.assertEqual(EmailLog.objects.count(), 2)

    def test_batch_with_category(self):
        """
        When a batch submission contains categories, we should try to link the
        relevant events with a saved search log.
        """
        now = date.today()
        log_uuid = uuid.uuid4().hex
        SavedSearchLog.objects.create(was_sent=True, recipient=self.user,
                                      recipient_email=self.user.email,
                                      uuid=log_uuid, new_jobs=0,
                                      backfill_jobs=0)
        self.events = ['open']
        category = '(stuff|%s)' % log_uuid
        message = self.make_messages(now, 3, [category])
        self.client.post(reverse('batch_message_digest'),
                         data=message,
                         content_type='text/json',
                         HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(EmailLog.objects.count(), 1)
        email_log = EmailLog.objects.get()
        self.assertIn(log_uuid, email_log.category)
        saved_search_log = SavedSearchLog.objects.get()
        self.assertEqual(saved_search_log.uuid, log_uuid)
        # One saved search log can handle multiple sendgrid responses
        # (multiple bounces, clicks, opens, etc per email).
        self.assertTrue(email_log in saved_search_log.sendgrid_response.all())
        self.assertTrue(saved_search_log.was_received)

    def test_batch_with_multiple_categories(self):
        """
        Manually-sent saved search emails will contain multiple categories.
        Ensure nothing breaks horribly when multiple categories are used.
        If one of the categories is Production, remove it and continue
        processing (creating EmailLogs, etc). If one of the categories is QC,
        Staging, Jenkins, or Local, stop processing the event.
        """
        self.assertEqual(EmailLog.objects.count(), 0)
        now = date.today()
        categories = ["My.jobs Email", "Production"]
        message = self.make_messages(now, categories=categories)
        self.client.post(reverse('batch_message_digest'),
                         data=message,
                         content_type='text/json',
                         HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(EmailLog.objects.count(), 3)

        for category in ['QC', 'Staging', 'Jenkins', 'Local']:
            categories[1] = category
            message = self.make_messages(now, categories=categories)
            self.client.post(reverse('batch_message_digest'),
                             data=message,
                             content_type='text/json',
                             HTTP_AUTHORIZATION='BASIC %s' % self.auth)
            self.assertEqual(EmailLog.objects.count(), 3)

    def test_batch_bounce_message_digest(self):
        now = date.today()
        message = '[{{"email":"*****@*****.**","timestamp":"{0}",' \
                  '"event":"bounce","category":"My.jobs email redirect",' \
                  '"status":418,"reason":"I\'m a teapot!",' \
                  '"type":"bounced"}}]'.format(
                      time.mktime(now.timetuple()))
        response = self.client.post(reverse('batch_message_digest'),
                                    data=message,
                                    content_type='text/json',
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(len(mail.outbox), 1)
        email = mail.outbox.pop()
        self.assertEqual(email.subject,
                         'My.jobs email redirect failure')
        self.assertEqual(email.from_email, self.user.email)
        self.assertEqual(email.to, [settings.EMAIL_TO_ADMIN])
        for text in ["I'm a teapot!", '418']:
            self.assertTrue(text in email.body)

    def test_batch_month_old_message_digest_with_searches(self):
        """
        Posting data created a month ago should result in one EmailLog instance
        being created per message and one email being sent per user

        """

        # Create activation profile for user; Used when disabling an account
        custom_signals.create_activation_profile(sender=self,
                                                 user=self.user,
                                                 email=self.user.email)

        week_before_expiration = date.today() - timedelta(days=172)
        self.user.last_response = week_before_expiration - timedelta(days=1)
        self.user.save()
        SavedSearch(user=self.user).save()

        # Submit a batch of events created a month ago
        # The owners of these addresses should be sent an email
        messages = self.make_messages(week_before_expiration)
        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertTrue(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 3)
        self.assertEqual(
            EmailLog.objects.filter(
                received=week_before_expiration
            ).count(), 3
        )
        process_batch_events()
        self.assertEqual(len(mail.outbox), 1)

        user = User.objects.get(pk=self.user.pk)
        self.assertEqual(user.last_response, week_before_expiration)

    def test_batch_month_old_message_digest_no_searches(self):
        """
        Posting data created a month ago should result in no emails being sent
        if the user has no saved searches
        """

        # Create activation profile for user
        custom_signals.create_activation_profile(sender=self,
                                                 user=self.user,
                                                 email=self.user.email)

        month_ago = date.today() - timedelta(days=30)
        self.user.last_response = month_ago - timedelta(days=1)
        self.user.save()

        messages = self.make_messages(month_ago)
        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertTrue(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 3)
        self.assertEqual(
            EmailLog.objects.filter(
                received=month_ago
            ).count(), 3
        )
        process_batch_events()
        self.assertEqual(len(mail.outbox), 0)

    def test_batch_month_and_week_old_message_digest(self):
        """
        Posting data created a month and a week ago should result in one
        EmailLog instance being created per message, no emails being sent,
        and the user's opt-in status being set to False
        """

        # Create activation profile for user; Used when disabling an account
        custom_signals.create_activation_profile(sender=self,
                                                 user=self.user,
                                                 email=self.user.email)

        six_months_ago = date.today() - timedelta(days=180)
        self.user.last_response = six_months_ago - timedelta(days=1)
        self.user.save()

        # Submit a batch of events created a month and a week ago
        # The owners of these addresses should no longer receive email
        messages = self.make_messages(six_months_ago)
        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertTrue(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 3)
        self.assertEqual(
            EmailLog.objects.filter(
                received__lte=(date.today() - timedelta(days=180))
            ).count(), 3
        )
        process_batch_events()
        self.assertEqual(len(mail.outbox), 0)

        user = User.objects.get(pk=self.user.pk)
        self.assertFalse(user.opt_in_myjobs)
        self.assertTrue(user.last_response, six_months_ago)

    def test_invalid_batch_post(self):
        response = self.client.post(reverse('batch_message_digest'),
                                    data='this is invalid',
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' % self.auth)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(EmailLog.objects.count(), 0)

    def test_invalid_user(self):
        now = date.today()
        messages = self.make_messages(now)

        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json")
        self.assertEqual(response.status_code, 403)

        response = self.client.post(reverse('batch_message_digest'),
                                    data=messages,
                                    content_type="text/json",
                                    HTTP_AUTHORIZATION='BASIC %s' %
                                    base64.b64encode(
                                        'does%40not.exist:wrong_pass'))
        self.assertEqual(response.status_code, 403)

    def test_redirect_query_params(self):
        """
        If a user is redirected, the next parameter should not be missing query
        parameters.
        """
        # log out to force redirects
        self.client.post(reverse('auth_logout'))

        response = self.client.get(reverse('prm') + '?company=1')
        self.assertIn(urlencode({'next': '/prm/view?company=1'}),
                      response.get('Location'))

    def test_anonymous_continue_sending_mail(self):
        Session.objects.all().delete()
        self.user.last_response = date.today() - timedelta(days=7)
        self.user.save()

        # Navigating to the 'continue sending email' page while logged out...
        response = self.client.get(reverse('continue_sending_mail'))
        path = response.request.get('PATH_INFO')
        self.assertRedirects(response, reverse('home')+'?next='+path)

        # or with the wrong email address...
        response = self.client.get(reverse('continue_sending_mail') +
                                   '[email protected]')
        self.assertRedirects(response, reverse('home'))
        # should result in redirecting to the login page

        response = self.client.get(reverse('continue_sending_mail') +
                                   '?verify=%s' % self.user.user_guid)
        self.assertRedirects(response, reverse('home'))
        self.user = User.objects.get(pk=self.user.pk)
        self.assertEqual(self.user.last_response, date.today())

    def test_continue_sending_mail(self):
        self.user.last_response = date.today() - timedelta(days=7)
        self.user.save()

        response = self.client.get(reverse('continue_sending_mail'),
                                   data={'user': self.user}, follow=True)

        self.assertEqual(self.user.last_response,
                         date.today() - timedelta(days=7))
        self.assertRedirects(response, '/')
        self.user = User.objects.get(pk=self.user.pk)
        self.assertEqual(self.user.last_response, date.today())

    def test_redirect_autocreated_user(self):
        """
        When users are created with no password, their password_change
        flag is set to true; If this is the case, all pages except for
        a select few should redirect to the password change form
        """
        self.user.password_change = True
        self.user.save()
        self.user = User.objects.get(email=self.user.email)

        response = self.client.get(reverse('saved_search_main'))

        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, reverse('edit_account')+"#as-password")

        profile = ActivationProfile.objects.get_or_create(
            user=self.user,
            email=self.user.email)[0]
        response = self.client.get(reverse('registration_activate',
                                           args=[profile.activation_key]))

        self.assertEqual(response.status_code, 200)

        response = self.client.post(reverse('edit_account')+'?password',
                                    data={'password': '******',
                                          'new_password1': '7dY=Ybtk',
                                          'new_password2': '7dY=Ybtk'})

        # When models are updated, instances still reference old data
        self.user = User.objects.get(email=self.user.email)
        self.assertFalse(self.user.password_change)

        response = self.client.get(reverse('saved_search_main'))

        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'mysearches/saved_search_main.html')

    def test_inactive_user_nav(self):
        """ Test that inactive users can't access restricted apps"""
        inactive_user = UserFactory(email='*****@*****.**', is_active=False)
        self.client.login_user(inactive_user)
        response = self.client.get("/")
        soup = BeautifulSoup(response.content)
        self.assertFalse(soup.findAll('a', {'id': 'savedsearch-link'}))

    def test_user_account_settings(self):
        """
        Test that the communication portion of account settings is not
        present for inactive users
        """
        def assert_communication_settings_presence(is_verified, contents):
            """
            If is_active is True, assert that div#as-communication exists
            Else, assert that it does not exist
            """
            communication_div = contents.find('div',
                                              {'id': 'as-communication'})
            if is_verified is True:
                self.assertTrue(communication_div)
            else:
                self.assertFalse(communication_div)

        unverified_user = UserFactory(email='*****@*****.**',
                                      is_verified=False)

        for user in [self.user, unverified_user]:
            self.client.login_user(user)
            response = self.client.get(reverse('edit_account'))
            soup = BeautifulSoup(response.content)

            assert_communication_settings_presence(user.is_verified, soup)

    def test_case_insensitive_login(self):
        """
        Test that emails are case-insensitive when logging in
        """
        for email in [self.user.email, self.user.email.upper()]:
            response = self.client.post(reverse('home'),
                                        data={'username': email,
                                              'password': '******',
                                              'action': 'login'})

            self.assertEqual(response.status_code, 200)
            self.assertEqual(response.content, '{"url": null,' +
                                               ' "units": false,' +
                                               ' "gravatar_url": "' +
                                               self.user.get_gravatar_url(
                                                   size=100)+'",' +
                                               ' "validation": "valid"}')

            self.client.get(reverse('auth_logout'))

    def test_guid_cookies_login_and_off(self):
        """
        Tests logging in and recieving a guid cookie. Logging out deletes guid
        cookie.
        """
        response = self.client.post(reverse('home'),
                                    data={'username': self.user.email,
                                          'password': '******',
                                          'action': 'login'})

        self.assertTrue(response.cookies['myguid'])
        cookie_guid = response.cookies['myguid']
        guid = cookie_guid.value
        self.assertEqual(guid, self.user.user_guid)

        resp_logoff = self.client.post(reverse('auth_logout'))
        cookie_guid_off = resp_logoff.cookies['myguid']
        guid_off = cookie_guid_off.value
        self.assertEqual(guid_off, '')

    def test_jira_login(self):
        jira = JIRA(options=options, basic_auth=my_agent_auth)
        self.assertIsNotNone(jira)

    def test_anonymous_unsubscribe_all_myjobs_emails(self):
        Session.objects.all().delete()
        self.assertTrue(self.user.opt_in_myjobs)

        # Navigating to the unsubscribe page while logged out...
        response = self.client.get(reverse('unsubscribe_all'))
        path = response.request.get('PATH_INFO')
        self.assertRedirects(response, reverse('home')+'?next='+path)
        # or with the wrong email address...
        response = self.client.get(reverse('unsubscribe_all') +
                                   '[email protected]')
        # should result in the user's status remaining unchanged
        # and the user should be redirected to the login page
        self.assertRedirects(response, reverse('home'))
        self.user = User.objects.get(id=self.user.id)
        self.assertTrue(self.user.opt_in_myjobs)

        # Navigating to the unsubscribe page while logged out
        # and with the correct email address...
        self.client.get(reverse('unsubscribe_all') +
                        '?verify=%s' % self.user.user_guid)
        self.user = User.objects.get(id=self.user.id)
        # should result in the user's :opt_in_myjobs: attribute being
        # set to False
        self.assertFalse(self.user.opt_in_myjobs)

    def test_unsubscribe_all_myjobs_emails(self):
        self.assertTrue(self.user.opt_in_myjobs)

        self.client.get(reverse('unsubscribe_all'))
        self.user = User.objects.get(id=self.user.id)
        self.assertFalse(self.user.opt_in_myjobs)

    def test_opt_out_sends_notifications(self):
        """
        When a user creates a saved search for another user and that user opts
        out of My.jobs communications, the creator should get a My.jobs message
        and email notifying them of the opt-out.
        """

        # required fields for saved search
        company = CompanyFactory()
        partner = PartnerFactory(owner=company)

        creator = UserFactory(id=3, email='*****@*****.**')

        # should not have any messages
        self.assertFalse(creator.message_set.all())

        PartnerSavedSearch.objects.create(user=self.user, provider=company,
                                          created_by=creator,
                                          partner=partner)

        # simulate a user opting out
        self.user.opt_in_myjobs = False
        self.user.save()

        self.client.get(reverse('unsubscribe_all'))

        # creator should have a My.jobs message and email
        for body in [creator.message_set.first().body,
                     mail.outbox[0].body]: 
            self.assertIn(self.user.email, body)
            self.assertIn('unsubscribed from one or more saved search emails',
                          body)

        # email should be sent to right person
        self.assertIn(creator.email, mail.outbox[0].to)

    def test_unsubscribe_sends_notifications(self):
        """
        When a user unsubscribes from one or more saved searches, the user who
        created the saved search should recieve an email and notification.
        """

        # required fields for saved search
        company = CompanyFactory()
        partner = PartnerFactory(owner=company)

        creator = UserFactory(id=3, email='*****@*****.**')

        # should not have any messages
        self.assertFalse(creator.message_set.all())

        PartnerSavedSearch.objects.create(user=self.user, provider=company,
                                          created_by=creator,
                                          partner=partner)

        self.client.get(reverse('unsubscribe_all'))

        # creator should have a My.jobs message and email
        for body in [creator.message_set.first().body,
                     mail.outbox[0].body]: 
            self.assertIn(self.user.email, body)
            self.assertIn('unsubscribed from one or more saved search emails',
                          body)

        # email should be sent to right person
        self.assertIn(creator.email, mail.outbox[0].to)

    def test_toolbar_logged_in(self):
        self.client.login_user(self.user)
        response = self.client.get(reverse('toolbar'))
        expected_response = '"user_fullname": "*****@*****.**"'
        self.assertIn(expected_response, response.content)

    def test_toolbar_not_logged_in(self):
        Session.objects.all().delete()
        response = self.client.get(reverse('toolbar'))
        expected_response = '({"user_fullname": "", "user_gravatar": '\
                            '"", "employer": ""});'
        self.assertEqual(response.content, expected_response)

    def test_p3p(self):
        """
        make sure the P3P headers are being set

        """
        self.client.login_user(self.user)
        response = self.client.get(reverse('toolbar'))
        p3p = str(response["P3P"])
        self.assertEqual('CP="ALL' in p3p, True)

    def test_topbar_with_invalid_session(self):
        response = self.client.get(
            reverse('topbar'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')

        # ensure topbar shows logged in options
        self.assertIn(self.user.email, response.content)

        Session.objects.all().delete()
        response = self.client.get(
            reverse('topbar'), HTTP_X_REQUESTED_WITH='XMLHttpRequest')

        # ensure topbar shows logged out options
        self.assertIn("Login", response.content)

    def test_referring_site_in_topbar(self):
        self.client.get(
            reverse('toolbar') + '?site_name=Indianapolis%20Jobs&site=http%3A'
                                 '%2F%2Findianapolis.jobs&callback=foo',
            HTTP_REFERER='http://indianapolis.jobs')

        last_site = self.client.cookies.get('lastmicrosite').value
        last_name = self.client.cookies.get('lastmicrositename').value

        response = self.client.get(reverse('home'))
        self.assertIn(last_site, response.content)
        self.assertIn(last_name, response.content)

    def test_messages_in_topbar(self):
        self.client.login_user(self.user)
        for num_messages in range(1, 5):
            # The indicator in the topbar will display a max of three messages.
            # Test that the correct number of messages is displayed for all
            # possible counts.
            infos = MessageInfoFactory.create_batch(size=num_messages,
                                                    user=self.user)
            # Mark the first message as read to show that read messages are
            # not shown.
            infos[0].mark_read()

            response = self.client.get(reverse('home'))
            self.assertTrue('id="menu-inbox">%s<' % (num_messages-1, )
                            in response.content)
            if num_messages == 1:
                # The only message has been read in this instance; it should
                # not have been displayed.
                self.assertTrue('No new unread messages' in response.content,
                                'Iteration %s' % num_messages)
            for info in infos[1:4]:
                # Ensure that the 1-3 messages we expect are appearing on
                # the page.
                self.assertTrue('message=%s' % info.message.pk
                                in response.content,
                                'Iteration %s, %s not found' % (
                                    num_messages,
                                    'message=%s' % info.message.pk))
            for info in infos[4:]:
                # Ensure that any additional unread messages beyond 3 are not
                # displayed.
                self.assertFalse('message=%s' % info.message.pk
                                 in response.content,
                                 "Iteration %s, %s exists but shouldn't" % (
                                     num_messages,
                                     'message=%s' % info.message.pk))
            Message.objects.all().delete()

    def test_cas_logged_in(self):
        response = self.client.get(reverse('cas'), follow=True)
        self.assertEqual(response.redirect_chain[-1][0].split("?")[0],
                         'http://www.my.jobs/')

    def test_cas_not_logged_in(self):
        self.client.post(reverse('auth_logout'))
        response = self.client.get(reverse('cas'), follow=True)
        self.assertEqual(response.redirect_chain[-1][0],
                         'https://secure.my.jobs/?next=http://www.my.jobs/')

    def test_user_creation_source(self):
        """
        User.source should be set to the last microsite a new user visited,
        an explicity defined source, the current site, or
        https://secure.my.jobs.
        """
        self.client.post(reverse('home'),
                         {'action': 'register',
                          'email': '*****@*****.**',
                          'password1': '5UuYquA@',
                          'password2': '5UuYquA@'})
        user = User.objects.get(email='*****@*****.**')
        # settings.SITE.domain == jobs.directemployers.org.
        self.assertEqual(user.source, 'jobs.directemployers.org')

        self.client.get(
            reverse('toolbar') + '?site_name=Indianapolis%20Jobs&site=http'
                                 '%3A%2F%2Findianapolis.jobs&callback=foo',
            HTTP_REFERER='http://indianapolis.jobs')

        last_site = self.client.cookies.get('lastmicrosite').value
        self.assertEqual(last_site, 'http://indianapolis.jobs')

        self.client.post(reverse('home'),
                         {'action': 'register',
                          'email': '*****@*****.**',
                          'password1': '5UuYquA@',
                          'password2': '5UuYquA@'})

        user = User.objects.get(email='*****@*****.**')
        self.assertEqual(user.source, last_site)

    def test_contact_FAQ(self):
        """
        Tests the redirect feature when no FAQ is created or visible.
        Then creates FAQ and checks to make sure it does show.

        """
        response = self.client.post(reverse('contact_faq'))
        # checks redirect
        self.assertEqual(response.status_code, 302)

        faq = FAQ(question="1101", answer="13")
        faq.save()

        response = self.client.post(reverse('contact_faq'))
        self.assertEqual(response.status_code, 200)

        faq.is_visible = False
        faq.save()

        response = self.client.post(reverse('contact_faq'))
        # checks redirect
        self.assertEqual(response.status_code, 302)

    def test_changing_title_content(self):
        """
        Tests that the title logo on the login page changes based on url.

        """
        self.client.logout()
        response = self.client.get(reverse('home'))
        content = BeautifulSoup(response.content)
        title = content.select('div#title')[0]
        self.assertTrue('The Right Place for' in title.text)

        response = self.client.get(reverse('home') + '?next=/prm/view/')
        content = BeautifulSoup(response.content)
        title = content.select('div#title')[0]
        self.assertTrue('The new OFCCP regulations' in title.text)

    def test_manual_account_creation(self):
        self.client.logout()
        self.assertEqual(len(mail.outbox), 0)
        self.client.post(reverse('home'), data={'email': '*****@*****.**',
                                                'password1': '5UuYquA@',
                                                'password2': '5UuYquA@',
                                                'action': 'register'})
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject,
                         'Account Activation for my.jobs')
示例#32
0
class NewUserTests(SeleniumTestCase):

    """Tests Account creation"""

    def setUp(self):
        super(NewUserTests, self).setUp()
        company = CompanyFactory()
        self.user = UserFactory(first_name="John", last_name="Doe")
        admin_role = RoleFactory(company=company, name='Admin')
        self.user.roles.add(self.admin_role)

    def test_home_page_works(self):
        """
        As John, navigating to https://secure.my.jobs should send me to a page
        titled "My.jobs".
        """
        self.browser.get(self.live_server_url)
        self.assertIn(self.browser.title, 'My.jobs')

    def test_cant_log_in_without_account(self):
        """
        As John, I shouldn't be able to log into My.jobs without registering
        first.
        """
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # We're trying to access a private page while unauthenticated, which
        # should result in a next parameter being added.
        self.assertTrue('next=' in self.browser.current_url)

        # attempt to log in
        username = self.find('id_username')
        username.send_keys(self.user.email)
        self.find('id_password').send_keys(self.user.password)
        self.find('login').click()

        # If we've logged in, the next parameter should have went away. We
        # aren't expecting to be logged in right now as the password was bad.
        self.assertTrue('next=' in self.browser.current_url)

    def test_user_registration(self):
        """
        As John, I should be able to register on My.jobs and log in.
        """
        self.browser.get('/'.join([self.live_server_url, 'prm', 'view']))

        # register
        self.find('id_email').send_keys('*****@*****.**')
        self.find('id_password1').send_keys('aaAA11..')
        self.find('id_password2').send_keys('aaAA11..')
        self.find('register').click()

        try:
            WebDriverWait(self.browser, 10).until(
                expected_conditions.presence_of_element_located(
                    (By.ID, 'profile')))
        finally:
            self.assertEqual(self.find('profile').get_attribute(
                'innerHTML'),
                'Skip: Take me to my profile')

    def test_user_login(self):
        self.user.set_password("test")
        self.user.save()
        self.find('id_username').send_keys(self.user.email)
        self.find('id_password').send_keys("test")
        self.find('login').click()
示例#33
0
class EmailForwardTests(RedirectBase):
    def setUp(self):
        super(EmailForwardTests, self).setUp()
        self.redirect_guid = JOB['guid']
        self.redirect = RedirectFactory(buid=JOB['buid'],
                                        guid='{%s}' %
                                             uuid.UUID(self.redirect_guid))

        self.password = '******'
        self.user = UserFactory(email='*****@*****.**')
        self.user.set_password(self.password)
        self.user.save()

        self.contact = CompanyEmail.objects.create(
            buid=self.redirect.buid,
            email=self.user.email)

        self.email = self.user.email.replace('@', '%40')
        self.auth = {
            'bad': [
                '',
                'Basic %s' % base64.b64encode('bad%40email:wrong_pass')],
            'good':
                'Basic %s' % base64.b64encode('%s:%s' % (self.user.email.\
                                                         replace('@', '%40'),
                                                         self.password))}
        self.post_dict = {'to': '*****@*****.**',
                          'from': '*****@*****.**',
                          'text': 'Questions about stuff',
                          'html': '<b>Questions about stuff</b>',
                          'subject': 'Bad Email',
                          'attachments': 0}

        self.r = Replacer()
        self.r.replace('pysolr.Solr.search', mock_search)

    def tearDown(self):
        super(EmailForwardTests, self).tearDown()
        self.r.restore()

    def submit_email(self, use_data=True):
        """
        Helper method for submitting parsed emails. Ensures that the request
        returns a status of 200.

        Inputs:
        :use_data: Should we include post data; Default: True

        Outputs:
        :response: HttpResponse from email redirect view
        """
        auth = self.auth.get('good')
        kwargs = {'HTTP_AUTHORIZATION': auth}
        if use_data:
            kwargs['data'] = self.post_dict
        response = self.client.post(reverse('email_redirect'),
                                    **kwargs)
        self.assertEqual(response.status_code, 200)

        return response

    def assert_guid_email_responses_are_correct(self,
                                                redirect,
                                                job=None):
        """
        Helper method for validating parsed [email protected] emails.

        Inputs:
        :redirect: Redirect instance to use if a job is old
        :job: Solr result for a new job
        """
        email = mail.outbox.pop(0)
        self.assertEqual(email.from_email,
                         settings.DEFAULT_FROM_EMAIL)
        self.assertEqual(email.to, [self.post_dict['from']])
        self.assertEqual(email.subject, self.post_dict['subject'])

        # Emails turn lots of characters into HTML entities. Results from
        # Solr and the database do not. Unescape the email body so we can
        # compare the two.
        parser = HTMLParser.HTMLParser()
        body = parser.unescape(email.body)
        if job is not None:
            self.assertTrue(markdown.markdown(job['description']) in body)
        else:
            self.assertTrue(redirect.job_title in body)

    def test_jira_login(self):
        jira = JIRA(options=settings.options,
                    basic_auth=settings.my_agent_auth)
        self.assertIsNotNone(jira)

    def test_bad_authorization(self):
        for auth in self.auth.get('bad'):
            kwargs = {}
            if auth:
                # auth_value has a value, so we can pass an HTTP_AUTHORIZATION
                #    header
                kwargs['HTTP_AUTHORIZATION'] = auth
            response = self.client.post(reverse('email_redirect'),
                                        **kwargs)
            self.assertTrue(response.status_code, 403)

    def test_good_authorization(self):
        self.submit_email(use_data=False)

    def test_bad_email(self):
        self.submit_email()

        self.assertEqual(len(mail.outbox), 0)

    def test_bad_guid_email(self):
        self.post_dict['to'] = '*****@*****.**' % ('1'*32)
        self.post_dict['text'] = 'This address is not in the database'

        self.submit_email()

        email = mail.outbox.pop()
        self.assertEqual(email.subject, 'Email forward failure')
        self.assertTrue('There is no job associated with this address'
                        in email.body)

    def test_good_guid_email_new_job(self):
        self.post_dict['to'] = ['*****@*****.**' % self.redirect_guid]
        self.post_dict['subject'] = 'Email forward success'

        self.submit_email()
        self.assert_guid_email_responses_are_correct(self.redirect, JOB)
        email = mail.outbox.pop()
        # email.alternatives is a list of sets as follows:
        # [('html body', 'text/html')]
        alternatives = dict((part[1], part[0]) for part in email.alternatives)
        self.assertTrue(JOB['html_description'] in alternatives['text/html'])
        self.assertTrue(email.subject.startswith('[ReqID: %s]' % JOB['reqid']))

    def test_good_guid_email_new_job_no_user(self):
        self.contact.delete()

        self.post_dict['to'] = ['*****@*****.**' % self.redirect_guid]
        self.post_dict['subject'] = 'Email forward success'

        self.submit_email()
        self.assert_guid_email_responses_are_correct(self.redirect, JOB)

    def test_good_guid_email_old_job(self):
        guid = '1'*32
        redirect = RedirectFactory(guid='{%s}' % uuid.UUID(guid),
                                   buid=self.redirect.buid,
                                   uid=1)
        self.post_dict['to'] = ['*****@*****.**' % guid]
        self.post_dict['subject'] = 'Email forward success'

        self.submit_email()
        self.assert_guid_email_responses_are_correct(redirect)

        email = mail.outbox.pop()
        self.assertTrue('This job (%s) has expired.' % (
            redirect.job_title, ) in email.body)
        self.assertTrue(email.subject.startswith('[ReqID: Expired]'))

    def test_good_guid_email_old_job_no_user(self):
        self.contact.delete()

        guid = '1'*32
        redirect = RedirectFactory(guid='{%s}' % uuid.UUID(guid),
                                   buid=self.redirect.buid,
                                   uid=1)
        self.post_dict['to'] = ['*****@*****.**' % guid]
        self.post_dict['subject'] = 'Email forward success'

        self.submit_email()
        self.assert_guid_email_responses_are_correct(redirect)

    def test_email_with_name(self):
        self.post_dict['to'] = 'User <*****@*****.**>' % self.redirect_guid
        self.post_dict['subject'] = 'Email forward success'

        self.submit_email()

        email = mail.outbox.pop()

    def test_no_emails(self):
        self.post_dict.pop('to')

        self.submit_email()

        self.assertEqual(len(mail.outbox), 0)

    def test_too_many_emails(self):
        self.post_dict['to'] = '[email protected], [email protected]'

        self.submit_email()

        self.assertEqual(len(mail.outbox), 0)

    def test_prm_email(self):
        """
        If [email protected] is included as a recipient, we repost this email to
        My.jobs. This is a straight post, which we don't want to do in a
        testing environment. If we receive a 200 status code and no emails
        were sent, this was reasonably likely to have completed successfully.
        """
        prm_list = ['*****@*****.**', '*****@*****.**']

        for email in prm_list:
            # SendGrid adds [email protected] to the 'envelope' JSON string
            # if it appears as a BCC
            self.post_dict['envelope'] = '{"to":["%s"]}' % email

            response = self.submit_email()
            self.assertEqual(response.content, 'reposted')
            self.assertEqual(len(mail.outbox), 0)

        del self.post_dict['envelope']

        for email in prm_list:
            self.post_dict['to'] = email

            response = self.submit_email()
            self.assertEqual(response.content, 'reposted')
            self.assertEqual(len(mail.outbox), 0)