Пример #1
0
class ReminderEmailTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.client = LocalizingClient()

    @mock.patch_object(Site.objects, 'get_current')
    def test_reminder_email(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.send_email_reminder'),
                                    {'username': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        eq_(1, len(mail.outbox))
        email = mail.outbox[0]
        assert email.subject.find('Email Address Reminder') == 0
        assert 'testuser' in email.body

    @mock.patch_object(Site.objects, 'get_current')
    def test_unknown_user_no_email_sent(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.send_email_reminder'),
                                    {'username': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        eq_(0, len(mail.outbox))
Пример #2
0
class ReminderEmailTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.client = LocalizingClient()

    @mock.patch_object(Site.objects, 'get_current')
    def test_reminder_email(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.send_email_reminder'),
                                    {'username': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        eq_(1, len(mail.outbox))
        email = mail.outbox[0]
        assert email.subject.find('Email Address Reminder') == 0
        assert 'testuser' in email.body

    @mock.patch_object(Site.objects, 'get_current')
    def test_unknown_user_no_email_sent(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.send_email_reminder'),
                                    {'username': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        eq_(0, len(mail.outbox))
Пример #3
0
    def test_invalid_slugs(self, get_current):
        """Slugs cannot contain /."""
        get_current.return_value.domain = 'testserver'
        client = LocalizingClient()
        client.login(username='******', password='******')
        data = new_document_data()
        error = 'The slug provided is not valid.'

        data['slug'] = 'inva/lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, error)

        data['slug'] = 'no-question-marks?'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, error)

        data['slug'] = 'no+plus'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, error)

        data['slug'] = 'valid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertRedirects(response, reverse('wiki.document_revisions',
                                               args=[data['slug']],
                                               locale='en-US'))
Пример #4
0
    def test_redirect_can_be_clobbered(self):
        """When an attempt is made to retitle an article, and another article
        with that title exists but is a redirect, there should be no errors and
        the redirect should be replaced."""
        client = LocalizingClient()
        client.login(username='******', password='******')

        exist_title = "Existing doc"
        exist_slug = "existing-doc"

        # Create a new doc.
        data = new_document_data()
        data.update({ "title": exist_title, "slug": exist_slug })
        resp = client.post(reverse('wiki.new_document'), data)
        eq_(302, resp.status_code)

        # Change title and slug
        data.update({'form': 'rev', 
                     'title': "Changed title", 
                     'slug': "changed-title"})
        resp = client.post(reverse('wiki.edit_document', args=[exist_slug]), 
                           data)
        eq_(302, resp.status_code)

        # Change title and slug back to originals, clobbering the redirect
        data.update({'form': 'rev', 
                     'title': exist_title, 
                     'slug': exist_slug})
        resp = client.post(reverse('wiki.edit_document', args=["changed-title"]), 
                           data)
        eq_(302, resp.status_code)
Пример #5
0
    def test_invalid_slug(self):
        """Slugs cannot contain "$", but can contain "/"."""
        client = LocalizingClient()
        client.login(username='******', password='******')
        data = new_document_data()

        data['title'] = 'valid slug'
        data['slug'] = 'valid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertRedirects(response, reverse('wiki.document',
                                               args=[data['slug']],
                                               locale='en-US'))

        # Slashes should be fine
        data['title'] = 'valid with slash'
        data['slug'] = 'va/lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertRedirects(response, reverse('wiki.document',
                                               args=[data['slug']],
                                               locale='en-US'))

        # Dollar sign is reserved for verbs
        data['title'] = 'invalid with dollars'
        data['slug'] = 'inva$lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, 'The slug provided is not valid.')

        # Question mark is reserved for query params
        data['title'] = 'invalid with questions'
        data['slug'] = 'inva?lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, 'The slug provided is not valid.')
Пример #6
0
    def test_title_slug_collision_errors(self):
        """When an attempt is made to retitle an article and another with that
        title already exists, there should be form errors"""
        client = LocalizingClient()
        client.login(username='******', password='******')

        exist_title = "Existing doc"
        exist_slug = "existing-doc"

        # Create a new doc.
        data = new_document_data()
        data.update({ "title": exist_title, "slug": exist_slug })
        resp = client.post(reverse('wiki.new_document'), data)
        eq_(302, resp.status_code)

        # Create another new doc.
        data = new_document_data()
        data.update({ "title": 'Some new title', "slug": 'some-new-title' })
        response = client.post(reverse('wiki.new_document'), data)
        eq_(302, resp.status_code)

        # Now, post an update with duplicate slug and title
        data.update({
            'form': 'rev',
            'title': exist_title,
            'slug': exist_slug
        })
        resp = client.post(reverse('wiki.edit_document', args=['some-new-title']), data)
        eq_(200, resp.status_code)
        p = pq(resp.content)

        ok_(p.find('.errorlist').length > 0)
        ok_(p.find('.errorlist a[href="#id_title"]').length > 0)
        ok_(p.find('.errorlist a[href="#id_slug"]').length > 0)
Пример #7
0
    def test_review_tags(self):
        client = LocalizingClient()
        client.login(username='******', password='******')

        data = new_document_data()
        data.update({'review_tags':['editorial']})
        response = client.post(reverse('wiki.new_document'), data)

        doc = Document.objects.get(slug="a-test-article")

        combos = (
            ([], 0, 0, 0, 0),
            (['technical',], 1, 1, 0, 0),
            (['editorial',], 0, 0, 1, 1),
            (['technical', 'editorial',], 1, 1, 1, 1),
        )

        for tags, a, b, c, d in combos:

            # Edit the page and set the tags for this test
            data.update({ 'form': 'rev', 'review_tags': tags })
            response = client.post(reverse('wiki.edit_document', args=[doc.slug]), data)

            response = client.get(reverse('docs.views.docs'))
            page = pq(response.content)

            # Check for the section itself, and then the doc 
            eq_(a, page('div#review-technical').length)
            eq_(b, page("div#review-technical ul li h4 a:contains('%s')" %
                doc.title).length)
            eq_(c, page('div#review-editorial').length)
            eq_(d, page("div#review-editorial ul li h4 a:contains('%s')" %
                doc.title).length)
Пример #8
0
class AppsViewsTest(test_utils.TestCase):

    def setUp(self):
        self.client = LocalizingClient()

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_newsletter')

        r = self.client.post(url,
                {'format': 'html',
                 'email': '*****@*****.**',
                 'agree': 'checked'},
            follow=True)
        eq_(200, r.status_code)
        # assert thank you message
        self.assertContains(r, 'Thank you')
        eq_(1, subscribe.call_count)

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_newsletter')
        r = self.client.post(url, {'format': 1, 'email': 'nope'})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, 'Enter a valid e-mail address.')
        self.assertContains(r, 'Select a valid choice.')
        self.assertContains(r, 'You must agree to the privacy policy.')
Пример #9
0
class AppsViewsTest(test_utils.TestCase):
    def setUp(self):
        self.client = LocalizingClient()

    def test_apps_menu_item(self):
        url = reverse("landing.views.home")
        r = self.client.get(url)
        eq_(200, r.status_code)
        doc = pq(r.content)
        nav_sub_topics = doc.find("ul#nav-sub-topics")
        ok_(nav_sub_topics)
        apps_item = nav_sub_topics.find("li#nav-sub-apps")
        eq_("Apps", apps_item.text())

    def test_apps(self):
        url = reverse("landing.views.apps")
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)
        doc = pq(r.content)
        signup_form = doc.find("form.fm-subscribe")
        eq_(reverse("apps_subscription", locale="en-US"), signup_form.attr("action"))

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = True
        url = reverse("landing.views.apps_subscription")
        r = self.client.post(url, {"format": "html", "email": "*****@*****.**", "agree": "checked"}, follow=True)
        eq_(200, r.status_code)
        # assert thank you message
        self.assertContains(r, "Thank you")
        eq_(1, subscribe.call_count)

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription_ajax(self, subscribe):
        subscribe.return_value = True
        url = reverse("landing.views.apps_subscription")
        r = self.client.post(
            url,
            {"format": "html", "email": "*****@*****.**", "agree": "checked"},
            HTTP_X_REQUESTED_WITH="XMLHttpRequest",
        )
        eq_(200, r.status_code)
        # assert thank you message
        self.assertContains(r, "Thank you")
        self.assertNotContains(r, "<html")
        self.assertNotContains(r, "<head>")
        self.assertNotContains(r, "<title>")
        eq_(1, subscribe.call_count)

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse("landing.views.apps_subscription")
        r = self.client.post(url, {"format": 1, "email": "nope"})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, "Enter a valid e-mail address.")
        self.assertContains(r, "Select a valid choice.")
        self.assertContains(r, "You must agree to the privacy policy.")
Пример #10
0
    def test_invalid_slug(self):
        """Slugs cannot contain /."""
        client = LocalizingClient()
        client.login(username='******', password='******')
        data = new_document_data()
        data['slug'] = 'inva/lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, 'The slug provided is not valid.')

        data['slug'] = 'valid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertRedirects(response, reverse('wiki.document_revisions',
                                               args=[data['slug']],
                                               locale='en-US'))
Пример #11
0
 def test_changing_products(self):
     """Changing products works as expected."""
     client = LocalizingClient()
     client.login(username='******', password='******')
     d, r = doc_rev()
     data = new_document_data()
     data.update({'products': ['desktop', 'sync'],
                  'form': 'doc'})
     client.post(reverse('wiki.edit_document', args=[d.slug]), data)
     tags_eq(d, ['desktop', 'sync'])
     data.update({'products': ['mobile'],
                  'form': 'doc'})
     client.post(reverse('wiki.edit_document', args=[data['slug']]), data)
     tags_eq(d, ['mobile'])
Пример #12
0
 def test_retitling_ignored_for_iframe(self):
     """When the title of an article is edited in an iframe, the change is
     ignored."""
     client = LocalizingClient()
     client.login(username='******', password='******')
     new_title = 'Some New Title'
     d, r = doc_rev()
     old_title = d.title
     data = new_document_data()
     data.update({'title': new_title,
                  'slug': d.slug,
                  'form': 'rev'})
     client.post('%s?iframe=1' % reverse('wiki.edit_document', args=[d.slug]), data)
     eq_(old_title, Document.uncached.get(slug=d.slug).title)
     assert "REDIRECT" not in Document.uncached.get(title=old_title).html
Пример #13
0
    def test_invalid_reserved_term_slug(self):
        """Slugs should not collide with reserved URL patterns"""
        client = LocalizingClient()
        client.login(username='******', password='******')
        data = new_document_data()

        # TODO: This is info derived from urls.py, but unsure how to DRY it
        reserved_slugs = (
            'ckeditor_config.js',
            'watch-ready-for-review',
            'unwatch-ready-for-review',
            'watch-approved',
            'unwatch-approved',
            '.json',
            'new',
            'all',
            'preview-wiki-content',
            'category/10',
            'needs-review/technical',
            'needs-review/',
            'feeds/atom/all/',
            'feeds/atom/needs-review/technical',
            'feeds/atom/needs-review/',
            'tag/tasty-pie'
        )

        for term in reserved_slugs:
            data['title'] = 'invalid with %s' % term
            data['slug'] = term
            response = client.post(reverse('wiki.new_document'), data)
            self.assertContains(response, 'The slug provided is not valid.')
Пример #14
0
    def test_invalid_slug(self, get_current):
        """Slugs cannot contain /."""
        get_current.return_value.domain = 'testserver'
        client = LocalizingClient()
        client.login(username='******', password='******')
        data = new_document_data()
        data['slug'] = 'inva/lid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertContains(response, 'The slug provided is not valid.')

        data['slug'] = 'valid'
        response = client.post(reverse('wiki.new_document'), data)
        self.assertRedirects(
            response,
            reverse('wiki.document_revisions',
                    args=[data['slug']],
                    locale='en-US'))
Пример #15
0
 def test_retitling(self):
     """When the title of an article is edited, a redirect is made."""
     # Not testing slug changes separately; the model tests cover those plus
     # slug+title changes. If title changes work in the view, the rest
     # should also.
     client = LocalizingClient()
     client.login(username='******', password='******')
     new_title = 'Some New Title'
     d, r = doc_rev()
     old_title = d.title
     data = new_document_data()
     data.update({'title': new_title,
                  'slug': d.slug,
                  'form': 'doc'})
     client.post(reverse('wiki.edit_document', args=[d.slug]), data)
     eq_(new_title, Document.uncached.get(slug=d.slug).title)
     assert Document.uncached.get(title=old_title).redirect_url()
Пример #16
0
 def test_changing_metadata(self):
     """Changing metadata works as expected."""
     client = LocalizingClient()
     client.login(username='******', password='******')
     d, r = doc_rev()
     data = new_document_data()
     data.update({'firefox_versions': [1, 2, 3],
                  'operating_systems': [1, 3],
                  'form': 'doc'})
     client.post(reverse('wiki.edit_document', args=[d.slug]), data)
     eq_(3, d.firefox_versions.count())
     eq_(2, d.operating_systems.count())
     data.update({'firefox_versions': [1, 2],
                  'operating_systems': [2],
                  'form': 'doc'})
     client.post(reverse('wiki.edit_document', args=[data['slug']]), data)
     eq_(2, d.firefox_versions.count())
     eq_(1, d.operating_systems.count())
Пример #17
0
class AppsViewsTest(SkippedTestCase):

    def setUp(self):
        self.client = LocalizingClient()
        super(AppsViewsTest, self).setUp()

    def _good_newsletter_post(self):
        url = reverse('landing.views.apps_newsletter')

        r = self.client.post(url,
                {'format': 'html',
                 'country': 'pt',
                 'email': '*****@*****.**',
                 'agree': 'checked'},
            follow=True)
        eq_(200, r.status_code)

        return r

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = {'status': 'success'}
        r = self._good_newsletter_post()
        # assert thank you message
        self.assertContains(r, 'Thank you')
        eq_(1, subscribe.call_count)

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_newsletter')
        r = self.client.post(url, {'format': 1, 'email': 'nope'})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, 'Enter a valid e-mail address.')
        self.assertContains(r, 'Select a valid choice.')
        self.assertContains(r, 'You must agree to the privacy policy.')

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_exception_retry(self, subscribe):
        subscribe.side_effect = basket.base.BasketException("500!")
        subscribe.return_value = True
        self._good_newsletter_post()
        eq_(constance.config.BASKET_RETRIES, subscribe.call_count)
Пример #18
0
class AppsViewsTest(test_utils.TestCase):
    def setUp(self):
        self.client = LocalizingClient()

    def _good_newsletter_post(self):
        url = reverse('landing.views.apps_newsletter')

        r = self.client.post(url, {
            'format': 'html',
            'country': 'pt',
            'email': '*****@*****.**',
            'agree': 'checked'
        },
                             follow=True)
        eq_(200, r.status_code)

        return r

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = {'status': 'success'}
        r = self._good_newsletter_post()
        # assert thank you message
        self.assertContains(r, 'Thank you')
        eq_(1, subscribe.call_count)

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_newsletter')
        r = self.client.post(url, {'format': 1, 'email': 'nope'})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, 'Enter a valid e-mail address.')
        self.assertContains(r, 'Select a valid choice.')
        self.assertContains(r, 'You must agree to the privacy policy.')

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_exception_retry(self, subscribe):
        subscribe.side_effect = basket.base.BasketException("500!")
        subscribe.return_value = True
        self._good_newsletter_post()
        eq_(constance.config.BASKET_RETRIES, subscribe.call_count)
Пример #19
0
class ReminderEmailTestCase(TestCase):
    fixtures = ["test_users.json"]

    def setUp(self):
        self.client = LocalizingClient()

    @mock.patch_object(Site.objects, "get_current")
    def test_reminder_email(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = "dev.mo.org"

        response = self.client.post(reverse("users.send_email_reminder"), {"username": "******"}, follow=True)
        eq_(200, response.status_code)
        eq_(1, len(mail.outbox))
        email = mail.outbox[0]
        assert email.subject.find("Email Address Reminder") == 0
        assert "testuser" in email.body

    @mock.patch_object(Site.objects, "get_current")
    def test_unknown_user_no_email_sent(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = "dev.mo.org"

        response = self.client.post(reverse("users.send_email_reminder"), {"username": "******"}, follow=True)
        eq_(200, response.status_code)
        eq_(0, len(mail.outbox))

    @mock.patch_object(Site.objects, "get_current")
    def test_user_without_email_message(self, get_current):
        """Should send simple email reminder to user."""
        get_current.return_value.domain = "dev.mo.org"

        u = User.objects.get(username="******")
        u.email = ""
        u.save()

        response = self.client.post(reverse("users.send_email_reminder"), {"username": "******"}, follow=True)
        eq_(200, response.status_code)
        eq_(0, len(mail.outbox))
        ok_("Could not find email" in response.content)
        ok_("file a bug" in response.content)
Пример #20
0
class AppsViewsTest(SkippedTestCase):
    def setUp(self):
        self.client = LocalizingClient()
        super(AppsViewsTest, self).setUp()

    def _good_newsletter_post(self):
        url = reverse("landing.views.apps_newsletter")

        r = self.client.post(
            url, {"format": "html", "country": "pt", "email": "*****@*****.**", "agree": "checked"}, follow=True
        )
        eq_(200, r.status_code)

        return r

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = {"status": "success"}
        r = self._good_newsletter_post()
        # assert thank you message
        self.assertContains(r, "Thank you")
        eq_(1, subscribe.call_count)

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse("landing.views.apps_newsletter")
        r = self.client.post(url, {"format": 1, "email": "nope"})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, "Enter a valid e-mail address.")
        self.assertContains(r, "Select a valid choice.")
        self.assertContains(r, "You must agree to the privacy policy.")

    @patch("landing.views.basket.subscribe")
    def test_apps_subscription_exception_retry(self, subscribe):
        subscribe.side_effect = basket.base.BasketException("500!")
        subscribe.return_value = True
        self._good_newsletter_post()
        eq_(constance.config.BASKET_RETRIES, subscribe.call_count)
Пример #21
0
    def test_edit_midair_collision(self):
        client = LocalizingClient()
        client.login(username='******', password='******')

        # Post a new document.
        data = new_document_data()
        resp = client.post(reverse('wiki.new_document'), data)
        doc = Document.objects.get(slug=data['slug'])

        # Edit #1 starts...
        resp = client.get(reverse('wiki.edit_document', args=[doc.slug]))
        page = pq(resp.content)
        rev_id1 = page.find('input[name="current_rev"]').attr('value')

        # Edit #2 starts...
        resp = client.get(reverse('wiki.edit_document', args=[doc.slug]))
        page = pq(resp.content)
        rev_id2 = page.find('input[name="current_rev"]').attr('value')

        # Edit #2 submits successfully
        data.update({
            'form': 'rev',
            'content': 'This edit got there first',
            'current_rev': rev_id2
        })
        resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data)
        eq_(302, resp.status_code)

        # Edit #1 submits, but receives a mid-aired notification
        data.update({
            'form': 'rev',
            'content': 'This edit gets mid-aired',
            'current_rev': rev_id1
        })
        resp = client.post(reverse('wiki.edit_document', args=[doc.slug]), data)
        eq_(200, resp.status_code)

        ok_(unicode(MIDAIR_COLLISION).encode('utf-8') in resp.content,
            "Midair collision message should appear")
Пример #22
0
    def test_raw_section_edit(self):
        client = LocalizingClient()
        client.login(username='******', password='******')
        d, r = doc_rev("""
            <h1 id="s1">Head 1</h1>
            <p>test</p>
            <p>test</p>

            <h1 id="s2">Head 2</h1>
            <p>test</p>
            <p>test</p>

            <h1 id="s3">Head 3</h1>
            <p>test</p>
            <p>test</p>
        """)
        replace = """
            <h1 id="s2">Replace</h1>
            <p>replace</p>
        """
        expected = """
            <h1 id="s2">Replace</h1>
            <p>replace</p>
        """
        response = client.post('%s?section=s2&raw=true' %
                               reverse('wiki.edit_document', args=[d.slug]),
                               {"form": "rev",
                                "content": replace},
                               follow=True)
        eq_(normalize_html(expected), 
            normalize_html(response.content))

        expected = """
            <h1 id="s1">Head 1</h1>
            <p>test</p>
            <p>test</p>

            <h1 id="s2">Replace</h1>
            <p>replace</p>

            <h1 id="s3">Head 3</h1>
            <p>test</p>
            <p>test</p>
        """
        response = client.get('%s?raw=true' %
                               reverse('wiki.document', args=[d.slug]))
        eq_(normalize_html(expected), 
            normalize_html(response.content))
Пример #23
0
    def test_ban_view(self):
        testuser = User.objects.get(username="******")
        admin = User.objects.get(username="******")

        client = LocalizingClient()
        client.login(username="******", password="******")

        data = {"reason": "Banned by unit test."}
        ban_url = reverse("users.ban_user", kwargs={"user_id": testuser.id})

        resp = client.post(ban_url, data)
        eq_(302, resp.status_code)
        ok_(testuser.get_absolute_url() in resp["Location"])

        testuser_banned = User.objects.get(username="******")
        ok_(not testuser_banned.is_active)

        bans = UserBan.objects.filter(user=testuser, by=admin, reason="Banned by unit test.")
        ok_(bans.count())
Пример #24
0
class ChangeEmailTestCase(TestCase):
    fixtures = ['users.json']

    def setUp(self):
        self.client = LocalizingClient()
        # Create some notifications
        EventWatch.objects.create(content_type_id=1, watch_id=2,
                                  email='user47963@nowhere')

    @mock.patch_object(Site.objects, 'get_current')
    def test_user_change_email(self, get_current):
        """Send email to change user's email and then change it."""
        get_current.return_value.domain = 'su.mo.com'

        self.client.login(username='******', password='******')
        # Attempt to change email.
        response = self.client.post(reverse('users.change_email'),
                                    {'email': '*****@*****.**'},
                                    follow=True)
        eq_(200, response.status_code)

        # Be notified to click a confirmation link.
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]
        assert ec.activation_key in mail.outbox[0].body
        eq_('*****@*****.**', ec.email)

        # Visit confirmation link to change email.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        u = User.objects.get(username='******')
        eq_('*****@*****.**', u.email)

        # Notifications have been updated.
        # TODO: remove this after notifications model is updated.
        ew = EventWatch.objects.get()
        eq_('*****@*****.**', ew.email)
Пример #25
0
    def test_ban_view(self):
        testuser = User.objects.get(username='******')
        admin = User.objects.get(username='******')

        client = LocalizingClient()
        client.login(username='******', password='******')

        data = {'reason': 'Banned by unit test.'}
        ban_url = reverse('users.ban_user',
                          kwargs={'user_id': testuser.id})

        resp = client.post(ban_url, data)
        eq_(302, resp.status_code)
        ok_(testuser.get_absolute_url() in resp['Location'])

        testuser_banned = User.objects.get(username='******')
        ok_(not testuser_banned.is_active)

        bans = UserBan.objects.filter(user=testuser,
                                      by=admin,
                                      reason='Banned by unit test.')
        ok_(bans.count())
Пример #26
0
class ChangeEmailTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.client = LocalizingClient()

    @mock.patch_object(Site.objects, 'get_current')
    def test_user_change_email(self, get_current):
        """Send email to change user's email and then change it."""
        get_current.return_value.domain = 'su.mo.com'

        self.client.login(username='******', password='******')
        # Attempt to change email.
        response = self.client.post(reverse('users.change_email'),
                                    {'email': '*****@*****.**'},
                                    follow=True)
        eq_(200, response.status_code)

        # Be notified to click a confirmation link.
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]
        assert ec.activation_key in mail.outbox[0].body
        eq_('*****@*****.**', ec.email)

        # Visit confirmation link to change email.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        u = User.objects.get(username='******')
        eq_('*****@*****.**', u.email)

    @mock_get_deki_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_user_change_email_updates_mindtouch(self, get_current):
        """Send email to change user's email and then change it."""
        get_current.return_value.domain = 'su.mo.com'

        self.client.login(username='******', password='******')
        # Attempt to change email.
        response = self.client.post(reverse('users.change_email'),
                                    {'email': '*****@*****.**'},
                                    follow=True)
        eq_(200, response.status_code)

        # Be notified to click a confirmation link.
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]
        assert ec.activation_key in mail.outbox[0].body
        eq_('*****@*****.**', ec.email)

        # Visit confirmation link to change email.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        u = User.objects.get(username='******')
        eq_('*****@*****.**', u.email)

        if not settings.DEKIWIKI_MOCK:
            deki_id = u.get_profile().deki_user_id
            doc = get_deki_user_doc(u)
            eq_(str(deki_id), doc('user').attr('id'))
            eq_('*****@*****.**',
                doc('user').find('email').text())

    def test_user_change_email_same(self):
        """Changing to same email shows validation error."""
        self.client.login(username='******', password='******')
        user = User.objects.get(username='******')
        user.email = '*****@*****.**'
        user.save()
        response = self.client.post(reverse('users.change_email'),
                                    {'email': user.email})
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('This is your current email.', doc('ul.errorlist').text())

    def test_user_change_email_duplicate(self):
        """Changing to same email shows validation error."""
        self.client.login(username='******', password='******')
        email = '*****@*****.**'
        response = self.client.post(reverse('users.change_email'),
                                    {'email': email})
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('A user with that email address already exists.',
            doc('ul.errorlist').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_user_confirm_email_duplicate(self, get_current):
        """If we detect a duplicate email when confirming an email change,
        don't change it and notify the user."""
        get_current.return_value.domain = 'su.mo.com'
        self.client.login(username='******', password='******')
        old_email = User.objects.get(username='******').email
        new_email = '*****@*****.**'
        response = self.client.post(reverse('users.change_email'),
                                    {'email': new_email})
        eq_(200, response.status_code)
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]

        # Before new email is confirmed, give the same email to a user
        other_user = User.objects.filter(username='******')[0]
        other_user.email = new_email
        other_user.save()

        # Visit confirmation link and verify email wasn't changed.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('Unable to change email for user testuser',
            doc('.main h1').text())
        u = User.objects.get(username='******')
        eq_(old_email, u.email)
Пример #27
0
class LoginTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    @mock.patch_object(Site.objects, 'get_current')
    def test_bad_login_fails_both_backends(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        self.assertRaises(User.DoesNotExist, User.objects.get,
                          username='******')

        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        self.assertContains(response, 'Please enter a correct username and '
                                      'password.')

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_wont_redirect_to_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******',
                                     'next': login_uri},
                                    follow=True)
        eq_(200, response.status_code)
        for redirect_url, code in response.redirect_chain:
            ok_(login_uri not in redirect_url, "Found %s in redirect_chain"
                % login_uri)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_logged_in_message(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_("You are already logged in.", doc.find('div#content-main').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_redirects_to_next(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, {'next': '/en-US/demos/submit'},
                                   follow=True)
        eq_('http://testserver/en-US/demos/submit',
                                                response.redirect_chain[0][0])

    @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login')
    def test_mindtouch_disabled_login(self, mock_mindtouch_login):
        """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth."""
        # HACK: mock has an assert_called_with, but I want something like
        # never_called or call_count. Instead, I have this:
        trap = {'was_called': False}

        def my_mindtouch_login(username, password, force=False):
            trap['was_called'] = True
            return False

        mock_mindtouch_login.side_effect = my_mindtouch_login

        # Try to log in as a MindTouch user, assert that MindTouch auth was
        # never attempted.
        _old = settings.DEKIWIKI_ENDPOINT
        settings.DEKIWIKI_ENDPOINT = False
        self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        settings.DEKIWIKI_ENDPOINT = _old

        ok_(not trap['was_called'])

    @mock_mindtouch_login
    @mock_get_deki_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_mindtouch_creds_create_user_and_profile(self, get_current):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        get_current.return_value.domain = 'dev.mo.org'

        if not getattr(settings, 'DEKIWIKI_MOCK', False):
            # HACK: Ensure that expected user details are in MindTouch when not
            # mocking the API
            mt_email = '*****@*****.**'
            user_xml = MINDTOUCH_USER_XML % dict(username="******",
                    email=mt_email, fullname="None", status="active",
                    language="", timezone="-08:00", role="Contributor")
            DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount',
                                               user_xml=user_xml)
            passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % (
                settings.DEKIWIKI_ENDPOINT, '=testaccount',
                settings.DEKIWIKI_APIKEY)
            requests.put(passwd_url, data='theplanet')

        self.assertRaises(User.DoesNotExist, User.objects.get,
                          username='******')

        # Try to log in as a MindTouch user
        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)

        # Ensure there are no validation errors
        page = pq(response.content)
        eq_(0, page.find('.errorlist').length,
            "There should be no validation errors in login")

        # Login should have auto-created django user
        u = User.objects.get(username='******')
        eq_(True, u.is_active)
        ok_(u.get_profile())

        # Login page should show welcome back
        doc = pq(response.content)
        eq_('testaccount', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_clean_next_url_request_properties(self, get_current):
        '''_clean_next_url checks POST, GET, and REFERER'''
        get_current.return_value.domain = 'dev.mo.org'

        r = RequestFactory().get('/users/login', {'next': '/demos/submit'},
                                 HTTP_REFERER='referer-trumped-by-get')
        eq_('/demos/submit', _clean_next_url(r))
        r = RequestFactory().post('/users/login', {'next': '/demos/submit'})
        eq_('/demos/submit', _clean_next_url(r))
        r = RequestFactory().get('/users/login', HTTP_REFERER='/demos/submit')
        eq_('/demos/submit', _clean_next_url(r))

    @mock.patch_object(Site.objects, 'get_current')
    def test_clean_next_url_no_self_redirects(self, get_current):
        '''_clean_next_url checks POST, GET, and REFERER'''
        get_current.return_value.domain = 'dev.mo.org'

        for next in [settings.LOGIN_URL, settings.LOGOUT_URL]:
            r = RequestFactory().get('/users/login', {'next': next})
            eq_(None, _clean_next_url(r))

    @mock.patch_object(Site.objects, 'get_current')
    def test_clean_next_url_invalid_next_parameter(self, get_current):
        '''_clean_next_url cleans invalid urls'''
        get_current.return_value.domain = 'dev.mo.org'

        for next in self._invalid_nexts():
            r = RequestFactory().get('/users/login', {'next': next})
            eq_(None, _clean_next_url(r))

    @mock.patch_object(Site.objects, 'get_current')
    def test_login_invalid_next_parameter(self, get_current):
        '''Test with an invalid ?next=http://example.com parameter.'''
        get_current.return_value.domain = 'testserver.com'
        valid_next = reverse('home', locale=settings.LANGUAGE_CODE)

        for invalid_next in self._invalid_nexts():
            # Verify that _valid_ next parameter is set in form hidden field.
            response = self.client.get(urlparams(reverse('users.login'),
                                                 next=invalid_next))
            eq_(200, response.status_code)
            doc = pq(response.content)
            eq_(valid_next, doc('input[name="next"]')[0].attrib['value'])

            # Verify that it gets used on form POST.
            response = self.client.post(reverse('users.login'),
                                        {'username': '******',
                                         'password': '******',
                                         'next': invalid_next})
            eq_(302, response.status_code)
            eq_('http://testserver' + valid_next, response['location'])
            self.client.logout()

    def _invalid_nexts(self):
        return ['http://foobar.com/evil/', '//goo.gl/y-bad']
Пример #28
0
class RegisterTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    @mock_missing_get_deki_user
    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        response = self.client.post(reverse('users.register'),
                                    {'username': username,
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'foo'}, follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username=username)
        assert u.password.startswith('sha256')
        assert not u.is_active
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        key = RegistrationProfile.objects.all()[0].activation_key
        assert mail.outbox[0].body.find('activate/%s' % key) > 0

        # Now try to log in
        u.is_active = True
        u.save()
        response = self.client.post(reverse('users.login'),
                                    {'username': username,
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/en-US/', response.redirect_chain[0][0])

    @mock_missing_get_deki_user
    @mock_post_mindtouch_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_unicode_password(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        u_str = u'\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9'
        response = self.client.post(reverse('users.register', locale='ja'),
                                    {'username': username,
                                     'email': '*****@*****.**',
                                     'password': u_str,
                                     'password2': u_str}, follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username=username)
        u.is_active = True
        u.save()
        assert u.password.startswith('sha256')

        # make sure you can login now
        response = self.client.post(reverse('users.login', locale='ja'),
                                    {'username': username,
                                     'password': u_str}, follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/ja/', response.redirect_chain[0][0])

    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_activation(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        user = RegistrationProfile.objects.create_inactive_user(
            username, 'testpass', '*****@*****.**')
        assert not user.is_active
        key = RegistrationProfile.objects.all()[0].activation_key
        url = reverse('users.activate', args=[key])
        response = self.client.get(url, follow=True)
        eq_(200, response.status_code)
        user = User.objects.get(pk=user.pk)
        assert user.is_active

    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_claim_watches(self, get_current):
        """Claim user watches upon activation."""
        old, settings.CELERY_ALWAYS_EAGER = settings.CELERY_ALWAYS_EAGER, True

        get_current.return_value.domain = 'su.mo.com'

        watch(email='*****@*****.**', save=True)

        now = time()
        username = '******' % now
        user = RegistrationProfile.objects.create_inactive_user(
            username, 'testpass', '*****@*****.**')
        key = RegistrationProfile.objects.all()[0].activation_key
        self.client.get(reverse('users.activate', args=[key]), follow=True)

        # Watches are claimed.
        assert user.watch_set.exists()

        settings.CELERY_ALWAYS_EAGER = old

    @mock_get_deki_user
    def test_duplicate_username(self):
        response = self.client.post(reverse('users.register'),
                                    {'username': '******',
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'foo'}, follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_duplicate_mindtouch_username(self):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        response = self.client.post(reverse('users.register'),
                                    {'username': '******',
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'foo'}, follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_duplicate_email(self):
        User.objects.create(username='******', email='*****@*****.**').save()
        response = self.client.post(reverse('users.register'),
                                    {'username': '******',
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'foo'}, follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_no_match_passwords(self):
        response = self.client.post(reverse('users.register'),
                                    {'username': '******',
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'bar'}, follow=True)
        self.assertContains(response, 'must match')
Пример #29
0
class ChangeEmailTestCase(TestCase):
    fixtures = ['users.json']

    def setUp(self):
        self.client = LocalizingClient()

    def test_redirect(self):
        """Test our redirect from old url to new one."""
        response = self.client.get(reverse('users.old_change_email',
                                           locale='en-US'), follow=False)
        eq_(301, response.status_code)
        eq_('http://testserver/en-US/users/change_email', response['location'])

    @mock.patch.object(Site.objects, 'get_current')
    def test_user_change_email(self, get_current):
        """Send email to change user's email and then change it."""
        get_current.return_value.domain = 'su.mo.com'

        self.client.login(username='******', password='******')
        # Attempt to change email.
        response = self.client.post(reverse('users.change_email'),
                                    {'email': '*****@*****.**'},
                                    follow=True)
        eq_(200, response.status_code)

        # Be notified to click a confirmation link.
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]
        assert ec.activation_key in mail.outbox[0].body
        eq_('*****@*****.**', ec.email)

        # Visit confirmation link to change email.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        u = User.objects.get(username='******')
        eq_('*****@*****.**', u.email)

    def test_user_change_email_same(self):
        """Changing to same email shows validation error."""
        self.client.login(username='******', password='******')
        user = User.objects.get(username='******')
        user.email = '*****@*****.**'
        user.save()
        response = self.client.post(reverse('users.change_email'),
                                    {'email': user.email})
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('This is your current email.', doc('ul.errorlist').text())

    def test_user_change_email_duplicate(self):
        """Changing to same email shows validation error."""
        self.client.login(username='******', password='******')
        email = '*****@*****.**'
        User.objects.filter(username='******').update(email=email)
        response = self.client.post(reverse('users.change_email'),
                                    {'email': email})
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('A user with that email address already exists.',
            doc('ul.errorlist').text())

    @mock.patch.object(Site.objects, 'get_current')
    def test_user_confirm_email_duplicate(self, get_current):
        """If we detect a duplicate email when confirming an email change,
        don't change it and notify the user."""
        get_current.return_value.domain = 'su.mo.com'
        self.client.login(username='******', password='******')
        old_email = User.objects.get(username='******').email
        new_email = '*****@*****.**'
        response = self.client.post(reverse('users.change_email'),
                                    {'email': new_email})
        eq_(200, response.status_code)
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        ec = EmailChange.objects.all()[0]

        # Before new email is confirmed, give the same email to a user
        User.objects.filter(username='******').update(email=new_email)

        # Visit confirmation link and verify email wasn't changed.
        response = self.client.get(reverse('users.confirm_email',
                                           args=[ec.activation_key]))
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('Unable to change email for user rrosario',
            doc('#main h1').text())
        u = User.objects.get(username='******')
        eq_(old_email, u.email)
Пример #30
0
class LoginTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    @mock.patch_object(Site.objects, 'get_current')
    def test_bad_login_fails_both_backends(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        self.assertRaises(User.DoesNotExist, User.objects.get,
                          username='******')

        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        self.assertContains(response, 'Please enter a correct username and '
                                      'password.')

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_wont_redirect_to_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******',
                                     'next': login_uri},
                                    follow=True)
        eq_(200, response.status_code)
        for redirect_url, code in response.redirect_chain:
            ok_(login_uri not in redirect_url, "Found %s in redirect_chain"
                % login_uri)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_logged_in_message(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_("You are already logged in.", doc.find('div#content-main').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_redirects_to_next(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri,
                                    {'username': '******',
                                     'password': '******'},
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, {'next': '/en-US/demos/submit'},
                                   follow=True)
        eq_('http://testserver/en-US/demos/submit',
                                                response.redirect_chain[0][0])

    @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login')
    def test_mindtouch_disabled_login(self, mock_mindtouch_login):
        """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth."""
        # HACK: mock has an assert_called_with, but I want something like
        # never_called or call_count. Instead, I have this:
        trap = {'was_called': False}

        def my_mindtouch_login(username, password, force=False):
            trap['was_called'] = True
            return False

        mock_mindtouch_login.side_effect = my_mindtouch_login

        # Try to log in as a MindTouch user, assert that MindTouch auth was
        # never attempted.
        _old = settings.DEKIWIKI_ENDPOINT
        settings.DEKIWIKI_ENDPOINT = False
        self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        settings.DEKIWIKI_ENDPOINT = _old

        ok_(not trap['was_called'])

    @mock_mindtouch_login
    @mock_get_deki_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_mindtouch_creds_create_user_and_profile(self, get_current):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        get_current.return_value.domain = 'dev.mo.org'

        if not getattr(settings, 'DEKIWIKI_MOCK', False):
            # HACK: Ensure that expected user details are in MindTouch when not
            # mocking the API
            mt_email = '*****@*****.**'
            user_xml = MINDTOUCH_USER_XML % dict(username="******",
                    email=mt_email, fullname="None", status="active",
                    language="", timezone="-08:00", role="Contributor")
            DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount',
                                               user_xml=user_xml)
            passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % (
                settings.DEKIWIKI_ENDPOINT, '=testaccount',
                settings.DEKIWIKI_APIKEY)
            requests.put(passwd_url, data='theplanet')

        self.assertRaises(User.DoesNotExist, User.objects.get,
                          username='******')

        # Try to log in as a MindTouch user
        response = self.client.post(reverse('users.login'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)

        # Ensure there are no validation errors
        page = pq(response.content)
        eq_(0, page.find('.errorlist').length,
            "There should be no validation errors in login")

        # Login should have auto-created django user
        u = User.objects.get(username='******')
        eq_(True, u.is_active)
        ok_(u.get_profile())

        # Login page should show welcome back
        doc = pq(response.content)
        eq_('testaccount', doc.find('ul.user-state a:first').text())
Пример #31
0
class DemoViewsTest(test_utils.TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.testuser = User.objects.get(username='******')
        self.testuser.set_password(TESTUSER_PASSWORD)
        self.testuser.save()
        self.client = LocalizingClient()

    def test_submit_loggedout(self):
        r = self.client.get(reverse('demos_submit'))
        choices = pq(r.content)('p.choices')
        eq_(choices.find('a.button').length, 2)

    @logged_in
    def test_submit_loggedin(self):
        r = self.client.get(reverse('demos_submit'))
        assert pq(r.content)('form#demo-submit')

    @logged_in
    def test_submit_post_invalid(self):
        r = self.client.post(reverse('demos_submit'), data={})
        d = pq(r.content)
        assert d('form#demo-submit')
        assert d('li#field_title ul.errorlist')
        assert d('li#field_summary ul.errorlist')
        assert d('li#field_screenshot_1 ul.errorlist')
        assert d('li#field_demo_package ul.errorlist')
        assert d('li#field_license_name ul.errorlist')
        assert d('li#field_captcha ul.errorlist')
        assert d('li#field_accept_terms ul.errorlist')

    @logged_in
    @disable_captcha
    def test_submit_post_valid(self):

        # Create a valid demo zip file
        zf_fout = StringIO()
        zf = zipfile.ZipFile(zf_fout, 'w')
        zf.writestr('index.html', """<html></html>""")
        zf.close()

        # Create a new file for input
        zf_fin = StringIO(zf_fout.getvalue())
        zf_fin.name = 'demo.zip'

        r = self.client.post(reverse('demos_submit'), data=dict(
            title='Test submission',
            summary='This is a test demo submission',
            description='Some description goes here',
            tech_tags=('tech:audio', 'tech:video', 'tech:websockets',),
            screenshot_1=open(SCREENSHOT_PATH),
            demo_package=zf_fin,
            license_name='gpl',
            accept_terms='1',
        ))

        eq_(302, r.status_code)
        assert 'Location' in r
        assert 'test-submission' in r['Location']

        try:
            obj = Submission.objects.get(slug='test-submission')
            eq_('Test submission', obj.title)
        except Submission.DoesNotExist:
            assert False

        result_tags = [t.name for t in obj.taggit_tags.all_ns('tech:')]
        result_tags.sort()
        eq_(['tech:audio', 'tech:video', 'tech:websockets'], result_tags)


    @logged_in
    def test_edit_invalid(self):
        s = save_valid_submission()
        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.post(edit_url, data=dict())
        d = pq(r.content)
        assert d('form#demo-submit')
        assert d('li#field_title ul.errorlist')
        assert d('li#field_summary ul.errorlist')
        assert d('li#field_license_name ul.errorlist')

    @logged_in
    def test_edit_valid(self):
        s = save_valid_submission()
        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.post(edit_url, data=dict(
            title=s.title,
            summary='This is a test demo submission',
            description='Some description goes here',
            tech_tags=('tech:audio', 'tech:video', 'tech:websockets',),
            license_name='gpl',
            accept_terms='1',
        ))

        eq_(302, r.status_code)
        assert 'Location' in r
        assert 'hello-world' in r['Location']

        try:
            obj = Submission.objects.get(slug='hello-world')
            eq_('This is a test demo submission', obj.summary)
        except Submission.DoesNotExist:
            assert False

    def test_detail(self):
        s = save_valid_submission('hello world')

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        eq_(s.title, d('h1.page-title').text())
        edit_link = d('ul.manage a.edit')
        assert not edit_link

    def test_detail_censored(self):
        s = save_valid_submission('hello world')
        s.censored = True
        s.save()

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        eq_('Permission Denied', d('h1.page-title').text())

    def test_detail_censored_url(self):
        s = save_valid_submission('hello world')
        s.censored = True
        s.censored_url = "http://developer.mozilla.org"
        s.save()

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        eq_(302, r.status_code)
        eq_("http://developer.mozilla.org", r['Location'])

    @logged_in
    def test_creator_can_edit(self):
        s = save_valid_submission('hello world')

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        edit_link = d('ul#demo-manage a.edit')
        assert edit_link
        edit_url = reverse('demos_edit', args=[s.slug])
        eq_(edit_url, edit_link.attr("href"))

        r = self.client.get(edit_url)
        assert pq(r.content)('form#demo-submit')
        eq_('Save changes',
            pq(r.content)('p.fm-submit button[type="submit"]').text())

    @logged_in
    def test_hidden_field(self):
        s = save_valid_submission('hello world')

        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.get(edit_url)
        assert pq(r.content)('input[name="hidden"][type="checkbox"]')

    @logged_in
    def test_derby_field(self):
        s = save_valid_submission('hello world')

        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.get(edit_url)
        assert pq(r.content)('fieldset#devderby-submit')
Пример #32
0
class LoginTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    @mock.patch_object(Site.objects, 'get_current')
    def test_bad_login_fails_both_backends(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        self.assertRaises(User.DoesNotExist,
                          User.objects.get,
                          username='******')

        response = self.client.post(reverse('users.login'), {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        self.assertContains(response, 'Please enter a correct username and '
                            'password.')

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'

        response = self.client.post(reverse('users.login'), {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_wont_redirect_to_login(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri, {
            'username': '******',
            'password': '******',
            'next': login_uri
        },
                                    follow=True)
        eq_(200, response.status_code)
        for redirect_url, code in response.redirect_chain:
            ok_(login_uri not in redirect_url,
                "Found %s in redirect_chain" % login_uri)
        doc = pq(response.content)
        eq_('testuser', doc.find('ul.user-state a:first').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_logged_in_message(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri, {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, follow=True)
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_("You are already logged in.", doc.find('div#content-main').text())

    @mock.patch_object(Site.objects, 'get_current')
    def test_django_login_redirects_to_next(self, get_current):
        get_current.return_value.domain = 'dev.mo.org'
        login_uri = reverse('users.login')

        response = self.client.post(login_uri, {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        response = self.client.get(login_uri, {'next': '/en-US/demos/submit'},
                                   follow=True)
        eq_('http://testserver/en-US/demos/submit',
            response.redirect_chain[0][0])

    @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login')
    def test_mindtouch_disabled_login(self, mock_mindtouch_login):
        """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth."""
        # HACK: mock has an assert_called_with, but I want something like
        # never_called or call_count. Instead, I have this:
        trap = {'was_called': False}

        def my_mindtouch_login(username, password, force=False):
            trap['was_called'] = True
            return False

        mock_mindtouch_login.side_effect = my_mindtouch_login

        # Try to log in as a MindTouch user, assert that MindTouch auth was
        # never attempted.
        _old = settings.DEKIWIKI_ENDPOINT
        settings.DEKIWIKI_ENDPOINT = False
        response = self.client.post(reverse('users.login'), {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        settings.DEKIWIKI_ENDPOINT = _old

        ok_(not trap['was_called'])

    @mock_mindtouch_login
    @mock_get_deki_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_mindtouch_creds_create_user_and_profile(self, get_current):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        get_current.return_value.domain = 'dev.mo.org'

        if not getattr(settings, 'DEKIWIKI_MOCK', False):
            # HACK: Ensure that expected user details are in MindTouch when not
            # mocking the API
            mt_email = '*****@*****.**'
            user_xml = MINDTOUCH_USER_XML % dict(username="******",
                                                 email=mt_email,
                                                 fullname="None",
                                                 status="active",
                                                 language="",
                                                 timezone="-08:00",
                                                 role="Contributor")
            DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount',
                                               user_xml=user_xml)
            passwd_url = '%s/@api/deki/users/%s/password?apikey=%s' % (
                settings.DEKIWIKI_ENDPOINT, '=testaccount',
                settings.DEKIWIKI_APIKEY)
            requests.put(passwd_url, data='theplanet')

        self.assertRaises(User.DoesNotExist,
                          User.objects.get,
                          username='******')

        # Try to log in as a MindTouch user
        response = self.client.post(reverse('users.login'), {
            'username': '******',
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)

        # Ensure there are no validation errors
        page = pq(response.content)
        eq_(0,
            page.find('.errorlist').length,
            "There should be no validation errors in login")

        # Login should have auto-created django user
        u = User.objects.get(username='******')
        eq_(True, u.is_active)
        ok_(u.get_profile())

        # Login page should show welcome back
        doc = pq(response.content)
        eq_('testaccount', doc.find('ul.user-state a:first').text())
Пример #33
0
class MobileAAQTests(MobileTestCase):
    fixtures = ['users.json', 'questions.json']
    data = {
        'title':
        'A test question',
        'content':
        'I have this question that I hope...',
        'sites_affected':
        'http://example.com',
        'ff_version':
        '3.6.6',
        'os':
        'Intel Mac OS X 10.6',
        'plugins':
        '* Shockwave Flash 10.1 r53',
        'useragent':
        'Mozilla/5.0 (Macintosh; U; Intel Mac OS X '
        '10.6; en-US; rv:1.9.2.6) Gecko/20100625 '
        'Firefox/3.6.6'
    }

    def setUp(self):
        self.client = LocalizingClient()
        super(MobileAAQTests, self).setUp()

    def _new_question(self, post_it=False):
        """Post a new question and return the response."""
        url = urlparams(reverse('questions.new_question'),
                        product='desktop',
                        category='d1',
                        search='A test question',
                        showform=1)
        if post_it:
            return self.client.post(url, self.data, follow=True)
        return self.client.get(url, follow=True)

    def test_logged_out(self):
        """New question is posted through mobile."""
        response = self._new_question()
        eq_(200, response.status_code)
        self.assertTemplateUsed(response,
                                'questions/mobile/new_question_login.html')

    @mock.patch.object(Site.objects, 'get_current')
    def test_logged_in_get(self, get_current):
        """New question is posted through mobile."""
        get_current.return_value.domain = 'testserver'
        self.client.login(username='******', password='******')
        response = self._new_question()
        eq_(200, response.status_code)
        self.assertTemplateUsed(response, 'questions/mobile/new_question.html')

    @mock.patch.object(Site.objects, 'get_current')
    def test_logged_in_post(self, get_current):
        """New question is posted through mobile."""
        get_current.return_value.domain = 'testserver'
        self.client.login(username='******', password='******')
        response = self._new_question(post_it=True)
        eq_(200, response.status_code)
        assert Question.objects.filter(title='A test question')

    @mock.patch.object(Site.objects, 'get_current')
    def test_aaq_new_question_inactive(self, get_current):
        """New question is posted through mobile."""
        get_current.return_value.domain = 'testserver'
        # Log in first.
        self.client.login(username='******', password='******')
        # Then become inactive.
        u = User.objects.get(username='******')
        u.is_active = False
        u.save()

        response = self._new_question(post_it=True)
        eq_(200, response.status_code)
        self.assertTemplateUsed(response,
                                'questions/mobile/confirm_email.html')
Пример #34
0
class AppsViewsTest(test_utils.TestCase):
    def setUp(self):
        self.client = LocalizingClient()

    def test_apps_menu_item(self):
        url = reverse('landing.views.home')
        r = self.client.get(url)
        eq_(200, r.status_code)
        doc = pq(r.content)
        nav_sub_topics = doc.find('ul#nav-sub-topics')
        ok_(nav_sub_topics)
        apps_item = nav_sub_topics.find('li#nav-sub-apps')
        eq_('Apps', apps_item.text())

    def test_apps(self):
        url = reverse('landing.views.apps')
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)
        doc = pq(r.content)
        signup_form = doc.find('form.fm-subscribe')
        eq_(reverse('apps_subscription', locale='en-US'),
            signup_form.attr('action'))

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_subscription')
        r = self.client.post(url, {
            'format': 'html',
            'email': '*****@*****.**',
            'agree': 'checked'
        },
                             follow=True)
        eq_(200, r.status_code)
        # assert thank you message
        self.assertContains(r, 'Thank you')
        eq_(1, subscribe.call_count)

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_ajax(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_subscription')
        r = self.client.post(url, {
            'format': 'html',
            'email': '*****@*****.**',
            'agree': 'checked'
        },
                             HTTP_X_REQUESTED_WITH='XMLHttpRequest')
        eq_(200, r.status_code)
        # assert thank you message
        self.assertContains(r, 'Thank you')
        self.assertNotContains(r, '<html')
        self.assertNotContains(r, '<head>')
        self.assertNotContains(r, '<title>')
        eq_(1, subscribe.call_count)

    @patch('landing.views.basket.subscribe')
    def test_apps_subscription_bad_values(self, subscribe):
        subscribe.return_value = True
        url = reverse('landing.views.apps_subscription')
        r = self.client.post(url, {'format': 1, 'email': 'nope'})
        eq_(200, r.status_code)
        # assert error
        self.assertContains(r, 'Enter a valid e-mail address.')
        self.assertContains(r, 'Select a valid choice.')
        self.assertContains(r, 'You must agree to the privacy policy.')
Пример #35
0
class ProfileViewsTest(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    def _get_current_form_field_values(self, doc):
        # Scrape out the existing significant form field values.
        form = dict()
        for fn in ('email', 'fullname', 'title', 'organization', 'location',
                   'irc_nickname', 'bio', 'interests'):
            form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val()
        return form

    @attr('docs_activity')
    def test_profile_view(self):
        """A user profile can be viewed"""
        profile = UserProfile.objects.get(user__username='******')
        user = profile.user
        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.user.username,
            doc.find('#profile-head.vcard .nickname').text())
        eq_(profile.fullname, doc.find('#profile-head.vcard .fn').text())
        eq_(profile.title, doc.find('#profile-head.vcard .title').text())
        eq_(profile.organization, doc.find('#profile-head.vcard .org').text())
        eq_(profile.location, doc.find('#profile-head.vcard .loc').text())
        eq_('IRC: ' + profile.irc_nickname,
            doc.find('#profile-head.vcard .irc').text())
        eq_(profile.bio, doc.find('#profile-head.vcard .bio').text())

    def test_my_profile_view(self):
        u = User.objects.get(username='******')
        self.client.login(username=u.username, password=TESTUSER_PASSWORD)
        resp = self.client.get('/profile/')
        eq_(302, resp.status_code)
        ok_(
            reverse('devmo.views.profile_view', args=(
                u.username, )) in resp['Location'])

    def test_bug_698971(self):
        """A non-numeric page number should not cause an error"""
        (user, profile) = create_profile()

        url = '%s?page=asdf' % reverse('devmo.views.profile_view',
                                       args=(user.username, ))

        try:
            self.client.get(url, follow=True)
        except PageNotAnInteger:
            ok_(False, "Non-numeric page number should not cause an error")

    def test_profile_edit(self):
        profile = UserProfile.objects.get(user__username='******')
        user = profile.user
        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        eq_(0, doc.find('#profile-head .edit .button').length)

        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        edit_button = doc.find('#profile-head .edit #edit-profile')
        eq_(1, edit_button.length)

        url = edit_button.attr('href')
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.fullname,
            doc.find('#profile-edit input[name="fullname"]').val())
        eq_(profile.title, doc.find('#profile-edit input[name="title"]').val())
        eq_(profile.organization,
            doc.find('#profile-edit input[name="organization"]').val())
        eq_(profile.location,
            doc.find('#profile-edit input[name="location"]').val())
        eq_(profile.irc_nickname,
            doc.find('#profile-edit input[name="irc_nickname"]').val())

        new_attrs = dict(
            email='*****@*****.**',
            fullname="Another Name",
            title="Another title",
            organization="Another org",
        )

        r = self.client.post(url, new_attrs, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)
        eq_(new_attrs['fullname'], doc.find('#profile-head .main .fn').text())
        eq_(new_attrs['title'], doc.find('#profile-head .info .title').text())
        eq_(new_attrs['organization'],
            doc.find('#profile-head .info .org').text())

        profile = UserProfile.objects.get(user__username=user.username)
        eq_(new_attrs['fullname'], profile.fullname)
        eq_(new_attrs['title'], profile.title)
        eq_(new_attrs['organization'], profile.organization)

    def test_my_profile_edit(self):
        u = User.objects.get(username='******')
        self.client.login(username=u.username, password=TESTUSER_PASSWORD)
        resp = self.client.get('/profile/edit')
        eq_(302, resp.status_code)
        ok_(
            reverse('devmo.views.profile_edit', args=(
                u.username, )) in resp['Location'])

    def test_profile_edit_beta(self):
        user = User.objects.get(username='******')
        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        eq_(None, doc.find('input#id_beta').attr('checked'))

        form = self._get_current_form_field_values(doc)
        form['beta'] = True

        r = self.client.post(url, form, follow=True)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        eq_('checked', doc.find('input#id_beta').attr('checked'))

    def test_profile_edit_websites(self):
        user = User.objects.get(username='******')
        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        test_sites = {
            u'website': u'http://example.com/',
            u'twitter': u'http://twitter.com/lmorchard',
            u'github': u'http://github.com/lmorchard',
            u'stackoverflow': u'http://stackoverflow.com/users/lmorchard',
        }

        form = self._get_current_form_field_values(doc)

        # Fill out the form with websites.
        form.update(dict(
            ('websites_%s' % k, v) for k, v in test_sites.items()))

        # Submit the form, verify redirect to profile detail
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        # Verify the websites are saved in the profile.
        eq_(test_sites, p.websites)

        # Verify the saved websites appear in the editing form
        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        for k, v in test_sites.items():
            eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val())

        # Come up with some bad sites, either invalid URL or bad URL prefix
        bad_sites = {
            u'website': u'HAHAHA WHAT IS A WEBSITE',
            u'twitter': u'http://facebook.com/lmorchard',
            u'stackoverflow': u'http://overqueueblah.com/users/lmorchard',
        }
        form.update(dict(('websites_%s' % k, v) for k, v in bad_sites.items()))

        # Submit the form, verify errors for all of the bad sites
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-edit').length)
        tmpl = '#profile-edit #elsewhere .%s .errorlist'
        for n in ('website', 'twitter', 'stackoverflow'):
            eq_(1, doc.find(tmpl % n).length)

    def test_profile_edit_interests(self):
        user = User.objects.get(username='******')
        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing']

        form = self._get_current_form_field_values(doc)

        form['interests'] = ', '.join(test_tags)

        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [
            t.name.replace('profile:interest:', '')
            for t in p.tags.all_ns('profile:interest:')
        ]
        result_tags.sort()
        test_tags.sort()
        eq_(test_tags, result_tags)

        test_expertise = ['css', 'canvas']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [
            t.name.replace('profile:expertise:', '')
            for t in p.tags.all_ns('profile:expertise')
        ]
        result_tags.sort()
        test_expertise.sort()
        eq_(test_expertise, result_tags)

        # Now, try some expertise tags not covered in interests
        test_expertise = ['css', 'canvas', 'mobile', 'movies']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('.error #id_expertise').length)

    def test_bug_709938_interests(self):
        user = User.objects.get(username='******')
        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        test_tags = [
            u'science,Technology,paradox,knowledge,modeling,big data,'
            u'vector,meme,heuristics,harmony,mathesis universalis,'
            u'symmetry,mathematics,computer graphics,field,chemistry,'
            u'religion,astronomy,physics,biology,literature,'
            u'spirituality,Art,Philosophy,Psychology,Business,Music,'
            u'Computer Science'
        ]

        form = self._get_current_form_field_values(doc)

        form['interests'] = test_tags

        r = self.client.post(url, form, follow=True)
        eq_(200, r.status_code)
        doc = pq(r.content)
        eq_(1, doc.find('ul.errorlist li').length)
        assert ('Ensure this value has at most 255 characters'
                in doc.find('ul.errorlist li').text())

    def test_bug_698126_l10n(self):
        """Test that the form field names are localized"""
        user = User.objects.get(username='******')
        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        for field in r.context['form'].fields:
            # if label is localized it's a lazy proxy object
            ok_(
                not isinstance(r.context['form'].fields[field].label,
                               basestring), 'Field %s is a string!' % field)

    def _break(self, url, r):
        logging.debug("URL  %s" % url)
        logging.debug("STAT %s" % r.status_code)
        logging.debug("HEAD %s" % r.items())
        logging.debug("CONT %s" % r.content)
        ok_(False)
Пример #36
0
class RegisterTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.old_debug = settings.DEBUG
        settings.DEBUG = True
        self.client = LocalizingClient()
        self.client.logout()

    def tearDown(self):
        settings.DEBUG = self.old_debug

    @mock_missing_get_deki_user
    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        response = self.client.post(reverse('users.register'), {
            'username': username,
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username=username)
        assert u.password.startswith('sha256')
        assert not u.is_active
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        key = RegistrationProfile.objects.all()[0].activation_key
        assert mail.outbox[0].body.find('activate/%s' % key) > 0

        # Now try to log in
        u.is_active = True
        u.save()
        response = self.client.post(reverse('users.login'), {
            'username': username,
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/en-US/', response.redirect_chain[0][0])

    @mock_missing_get_deki_user
    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_posts_mindtouch_user(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        response = self.client.post(reverse('users.register'), {
            'username': username,
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username=username)
        assert u.password.startswith('sha256')
        assert not u.is_active
        eq_(1, len(mail.outbox))
        assert mail.outbox[0].subject.find('Please confirm your') == 0
        key = RegistrationProfile.objects.all()[0].activation_key
        assert mail.outbox[0].body.find('activate/%s' % key) > 0

        if not settings.DEKIWIKI_MOCK:
            deki_id = u.get_profile().deki_user_id
            doc = get_deki_user_doc(u)
            eq_(str(deki_id), doc('user').attr('id'))
            eq_(username, doc('username').text())

        # Now try to log in
        u.is_active = True
        u.save()
        response = self.client.post(reverse('users.login'), {
            'username': username,
            'password': '******'
        },
                                    follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/en-US/', response.redirect_chain[0][0])

    @mock_missing_get_deki_user
    @mock_put_mindtouch_user
    @mock_perform_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_retries_mindtouch_post(self, get_current):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        get_current.return_value.domain = 'dev.mo.org'
        now = time()
        username = '******' % now
        response = self.client.post(reverse('users.register'), {
            'username': username,
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        eq_(200, response.status_code)
        ok_("Please try again later." in response.content)
        self.assertRaises(User.DoesNotExist,
                          User.objects.get,
                          username=username)

    @mock_missing_get_deki_user
    @mock_post_mindtouch_user
    @mock_put_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_unicode_password(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        u_str = u'\xe5\xe5\xee\xe9\xf8\xe7\u6709\u52b9'
        response = self.client.post(reverse('users.register', locale='ja'), {
            'username': username,
            'email': '*****@*****.**',
            'password': u_str,
            'password2': u_str
        },
                                    follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username=username)
        u.is_active = True
        u.save()
        assert u.password.startswith('sha256')

        # make sure you can login now
        response = self.client.post(reverse('users.login', locale='ja'), {
            'username': username,
            'password': u_str
        },
                                    follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/ja/', response.redirect_chain[0][0])

    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_activation(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        now = time()
        username = '******' % now
        user = RegistrationProfile.objects.create_inactive_user(
            username, 'testpass', '*****@*****.**')
        assert not user.is_active
        key = RegistrationProfile.objects.all()[0].activation_key
        url = reverse('users.activate', args=[key])
        response = self.client.get(url, follow=True)
        eq_(200, response.status_code)
        user = User.objects.get(pk=user.pk)
        assert user.is_active

    @mock_put_mindtouch_user
    @mock_post_mindtouch_user
    @mock.patch_object(Site.objects, 'get_current')
    def test_new_user_claim_watches(self, get_current):
        """Claim user watches upon activation."""
        old, settings.CELERY_ALWAYS_EAGER = settings.CELERY_ALWAYS_EAGER, True

        get_current.return_value.domain = 'su.mo.com'

        watch(email='*****@*****.**', save=True)

        now = time()
        username = '******' % now
        user = RegistrationProfile.objects.create_inactive_user(
            username, 'testpass', '*****@*****.**')
        key = RegistrationProfile.objects.all()[0].activation_key
        self.client.get(reverse('users.activate', args=[key]), follow=True)

        # Watches are claimed.
        assert user.watch_set.exists()

        settings.CELERY_ALWAYS_EAGER = old

    @mock_get_deki_user
    def test_duplicate_username(self):
        response = self.client.post(reverse('users.register'), {
            'username': '******',
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_duplicate_mindtouch_username(self):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        response = self.client.post(reverse('users.register'), {
            'username': '******',
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_duplicate_email(self):
        User.objects.create(username='******', email='*****@*****.**').save()
        response = self.client.post(reverse('users.register'), {
            'username': '******',
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foo'
        },
                                    follow=True)
        self.assertContains(response, 'already exists')

    @mock_get_deki_user
    def test_no_match_passwords(self):
        response = self.client.post(reverse('users.register'), {
            'username': '******',
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'bar'
        },
                                    follow=True)
        self.assertContains(response, 'must match')
Пример #37
0
class DemoViewsTest(test_utils.TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        self.testuser = User.objects.get(username='******')
        self.testuser.set_password(TESTUSER_PASSWORD)
        self.testuser.save()
        self.client = LocalizingClient()

    def test_submit_loggedout(self):
        r = self.client.get(reverse('demos_submit'))
        choices = pq(r.content)('p.choices')
        eq_(choices.find('a.button').length, 2)

    @logged_in
    def test_submit_loggedin(self):
        r = self.client.get(reverse('demos_submit'))
        assert pq(r.content)('form#demo-submit')

    @logged_in
    def test_submit_post_invalid(self):
        r = self.client.post(reverse('demos_submit'), data={})
        d = pq(r.content)
        assert d('form#demo-submit')
        assert d('li#field_title ul.errorlist')
        assert d('li#field_summary ul.errorlist')
        assert d('li#field_screenshot_1 ul.errorlist')
        assert d('li#field_demo_package ul.errorlist')
        assert d('li#field_license_name ul.errorlist')
        assert d('li#field_captcha ul.errorlist')
        assert d('li#field_accept_terms ul.errorlist')

    @logged_in
    @disable_captcha
    def test_submit_post_valid(self):

        # Create a valid demo zip file
        zf_fout = StringIO()
        zf = zipfile.ZipFile(zf_fout, 'w')
        zf.writestr('index.html', """<html></html>""")
        zf.close()

        # Create a new file for input
        zf_fin = StringIO(zf_fout.getvalue())
        zf_fin.name = 'demo.zip'

        r = self.client.post(reverse('demos_submit'),
                             data=dict(
                                 title='Test submission',
                                 summary='This is a test demo submission',
                                 description='Some description goes here',
                                 tech_tags=(
                                     'tech:audio',
                                     'tech:video',
                                     'tech:websockets',
                                 ),
                                 screenshot_1=open(SCREENSHOT_PATH),
                                 demo_package=zf_fin,
                                 license_name='gpl',
                                 accept_terms='1',
                             ))

        eq_(302, r.status_code)
        assert 'Location' in r
        assert 'test-submission' in r['Location']

        try:
            obj = Submission.objects.get(slug='test-submission')
            eq_('Test submission', obj.title)
        except Submission.DoesNotExist:
            assert False

        result_tags = [t.name for t in obj.taggit_tags.all_ns('tech:')]
        result_tags.sort()
        eq_(['tech:audio', 'tech:video', 'tech:websockets'], result_tags)

    @logged_in
    def test_edit_invalid(self):
        s = save_valid_submission()
        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.post(edit_url, data=dict())
        d = pq(r.content)
        assert d('form#demo-submit')
        assert d('li#field_title ul.errorlist')
        assert d('li#field_summary ul.errorlist')
        assert d('li#field_license_name ul.errorlist')

    @logged_in
    def test_edit_valid(self):
        s = save_valid_submission()
        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.post(edit_url,
                             data=dict(
                                 title=s.title,
                                 summary='This is a test demo submission',
                                 description='Some description goes here',
                                 tech_tags=(
                                     'tech:audio',
                                     'tech:video',
                                     'tech:websockets',
                                 ),
                                 license_name='gpl',
                                 accept_terms='1',
                             ))

        eq_(302, r.status_code)
        assert 'Location' in r
        assert 'hello-world' in r['Location']

        try:
            obj = Submission.objects.get(slug='hello-world')
            eq_('This is a test demo submission', obj.summary)
        except Submission.DoesNotExist:
            assert False

    def test_detail(self):
        s = save_valid_submission('hello world')

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        eq_(s.title, d('h1.page-title').text())
        edit_link = d('ul.manage a.edit')
        assert not edit_link

    def test_detail_censored(self):
        s = save_valid_submission('hello world')
        s.censored = True
        s.save()

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        eq_('Permission Denied', d('h1.page-title').text())

    def test_detail_censored_url(self):
        s = save_valid_submission('hello world')
        s.censored = True
        s.censored_url = "http://developer.mozilla.org"
        s.save()

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        eq_(302, r.status_code)
        eq_("http://developer.mozilla.org", r['Location'])

    @logged_in
    def test_creator_can_edit(self):
        s = save_valid_submission('hello world')

        url = reverse('demos_detail', args=[s.slug])
        r = self.client.get(url)
        d = pq(r.content)
        edit_link = d('ul#demo-manage a.edit')
        assert edit_link
        edit_url = reverse('demos_edit', args=[s.slug])
        eq_(edit_url, edit_link.attr("href"))

        r = self.client.get(edit_url)
        assert pq(r.content)('form#demo-submit')
        eq_('Save changes',
            pq(r.content)('p.fm-submit button[type="submit"]').text())

    @logged_in
    def test_hidden_field(self):
        s = save_valid_submission('hello world')

        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.get(edit_url)
        assert pq(r.content)('input[name="hidden"][type="checkbox"]')

    @logged_in
    def test_derby_field(self):
        s = save_valid_submission('hello world')

        edit_url = reverse('demos_edit', args=[s.slug])
        r = self.client.get(edit_url)
        assert pq(r.content)('fieldset#devderby-submit')
Пример #38
0
class BrowserIDTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        # Ensure @ssl_required goes unenforced.
        settings.DEBUG = True
        # Set up some easily-testable redirects.
        settings.LOGIN_REDIRECT_URL = 'SUCCESS'
        settings.LOGIN_REDIRECT_URL_FAILURE = 'FAILURE'
        # BrowserID will squawk if this isn't set
        settings.SITE_URL = 'http://testserver'
        self.client = LocalizingClient()

    def test_invalid_post(self):
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'))
        eq_(302, resp.status_code)
        ok_('FAILURE' in resp['Location'])

    @mock.patch('users.views._verify_browserid')
    def test_invalid_assertion(self, _verify_browserid):
        _verify_browserid.return_value = None

        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'bad data'})
        eq_(302, resp.status_code)
        ok_('FAILURE' in resp['Location'])

    @mock_get_deki_user_by_email
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_django_user(self, _verify_browserid):
        _verify_browserid.return_value = {'email': '*****@*****.**'}

        # Posting the fake assertion to browserid_verify should work, with the
        # actual verification method mocked out.
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('SUCCESS' in resp['Location'])

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

    @mock_get_deki_user_by_email
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_explain_popup(self, _verify_browserid):
        _verify_browserid.return_value = {'email': '*****@*****.**'}
        resp = self.client.get(reverse('home', locale='en-US'))

        # Posting the fake assertion to browserid_verify should work, with the
        # actual verification method mocked out.
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_('1', resp.cookies.get('browserid_explained').value)

        resp = self.client.get(reverse('users.logout'), locale='en-US')

        # even after logout, cookie should prevent the toggle
        resp = self.client.get(reverse('home', locale='en-US'))
        eq_('1', self.client.cookies.get('browserid_explained').value)

    @mock_get_deki_user_by_email
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_mindtouch_user(self, _verify_browserid):
        if not settings.DEKIWIKI_ENDPOINT:
            # Don't even bother with this test, if there's no MindTouch API
            raise SkipTest()

        mt_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': mt_email}

        # Probably overkill but let's be sure we're testing the right thing.
        try:
            User.objects.get(email=mt_email)
            ok_(False, "The MindTouch user shouldn't exist in Django yet.")
        except User.DoesNotExist:
            pass

        if not getattr(settings, 'DEKIWIKI_MOCK', False):
            # HACK: Ensure that expected user details are in MindTouch when not
            # mocking the API
            user_xml = MINDTOUCH_USER_XML % dict(username="******",
                    email=mt_email, fullname="None", status="active",
                    language="", timezone="-08:00", role="Contributor")
            DekiUserBackend.put_mindtouch_user(deki_user_id='=testaccount',
                                               user_xml=user_xml)

        deki_user = DekiUserBackend.get_deki_user_by_email(mt_email)
        ok_(deki_user is not None, "The MindTouch user should exist")

        # Posting the fake assertion to browserid_verify should work, with the
        # actual verification method mocked out.
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('SUCCESS' in resp['Location'])

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

        # And, after all the above, there should be a Django user now.
        try:
            User.objects.get(email=mt_email)
        except User.DoesNotExist:
            ok_(False, "The MindTouch user should exist in Django now.")

    @attr('current')
    @mock.patch('dekicompat.backends.DekiUserBackend.get_deki_user_by_email')
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_mt_disabled(self, _verify_browserid,
                                              mock_get_deki_user_by_email):
        """On valid browserid assertion, when Django user is not found, yet
        MindTouch API disabled, there should be no attempt to look the user up
        in MindTouch"""
        mt_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': mt_email}

        # HACK: mock has an assert_called_with, but I want something like
        # never_called or call_count. Instead, I have this:
        trap = {'was_called': False}

        def my_get_deki_user_by_email(email):
            trap['was_called'] = True
            return False
        mock_get_deki_user_by_email.side_effect = my_get_deki_user_by_email

        _old = settings.DEKIWIKI_ENDPOINT
        settings.DEKIWIKI_ENDPOINT = False
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        settings.DEKIWIKI_ENDPOINT = _old

        # This should end up being a redirect to register
        eq_(302, resp.status_code)
        ok_('browserid_register' in resp['Location'])

        ok_(not trap['was_called'])

    @mock_missing_get_deki_user_by_email
    @mock_missing_get_deki_user
    @mock_post_mindtouch_user
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_new_account_creation(self,
                                                       _verify_browserid):
        new_username = '******'
        new_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': new_email}

        try:
            user = User.objects.get(email=new_email)
            ok_(False, "User for email should not yet exist")
        except User.DoesNotExist:
            pass

        if not getattr(settings, 'DEKIWIKI_MOCK', False):
            # HACK: When not mocking the MindTouch API, ensure that there's no
            # leftover user with the same name & email as what we want to
            # register
            import random
            rand_num = random.randint(0, 1000000)
            user_xml = MINDTOUCH_USER_XML % dict(
                    username="******" % (new_username, rand_num),
                    email="%s_%s" % (rand_num, new_email),
                    fullname="", status="inactive",
                    language="", timezone="-08:00",
                    role="Contributor")
            DekiUserBackend.put_mindtouch_user(
                    deki_user_id='=%s' % new_username, user_xml=user_xml)

        # Sign in with a verified email, but with no existing account
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)

        # This should be a redirect to the BrowserID registration page.
        redir_url = resp['Location']
        reg_url = reverse('users.browserid_register', locale='en-US')
        ok_(reg_url in redir_url)

        # And, as part of the redirect, the verified email address should be in
        # our session now.
        ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys())
        verified_email = self.client.session[SESSION_VERIFIED_EMAIL]
        eq_(new_email, verified_email)

        # Grab the redirect, assert that there's a create_user form present
        resp = self.client.get(redir_url)
        page = pq(resp.content)
        form = page.find('form#create_user')
        eq_(1, form.length)

        # There should be no error lists on first load
        eq_(0, page.find('.errorlist').length)

        # Submit the create_user form, with a chosen username
        resp = self.client.post(redir_url, {'username': '******',
                                            'action': 'register'})

        # The submission should result in a redirect to the session's redirect
        # value
        eq_(302, resp.status_code)
        redir_url = resp['Location']
        ok_('SUCCESS' in redir_url)

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

        if settings.DEKIWIKI_ENDPOINT:
            ok_(self.client.cookies.get('authtoken'), 'Should have set '
                                                      'authtoken cookie for '
                                                      'MindTouch')

        # Ensure that the user was created, and with the submitted username and
        # verified email address
        try:
            user = User.objects.get(email=new_email)
            eq_(new_username, user.username)
            eq_(new_email, user.email)
        except User.DoesNotExist:
            ok_(False, "New user should have been created")

    @mock_missing_get_deki_user_by_email
    @mock_post_mindtouch_user
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock_get_deki_user
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_existing_account_login(self,
                                                         _verify_browserid):
        """ Removed the existing user form: we don't auth the password with
        MindTouch anymore """
        new_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': new_email}

        try:
            User.objects.get(email=new_email)
            ok_(False, "User for email should not yet exist")
        except User.DoesNotExist:
            pass

        # Sign in with a verified email, but with no existing account
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)

        # This should be a redirect to the BrowserID registration page.
        redir_url = resp['Location']
        reg_url = reverse('users.browserid_register', locale='en-US')
        ok_(reg_url in redir_url)

        # And, as part of the redirect, the verified email address should be in
        # our session now.
        ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys())
        verified_email = self.client.session[SESSION_VERIFIED_EMAIL]
        eq_(new_email, verified_email)

        # Grab the redirect, assert that there's a create_user form present
        resp = self.client.get(redir_url)
        page = pq(resp.content)
        form = page.find('form#existing_user')
        eq_(0, form.length)

    @mock.patch('dekicompat.backends.DekiUserBackend.mindtouch_login')
    @mock.patch('users.views._verify_browserid')
    def test_mindtouch_disabled_redirect_login(self, _verify_browserid,
                                               mock_mindtouch_login):
        """When DEKIWIKI_ENDPOINT unavailable, skip MindTouch auth."""
        _verify_browserid.return_value = {'email': '*****@*****.**'}

        # HACK: mock has an assert_called_with, but I want something like
        # never_called or call_count. Instead, I have this:
        trap = {'was_called': False}

        def my_mindtouch_login(username, password, force=False):
            trap['was_called'] = True
            return False
        mock_mindtouch_login.side_effect = my_mindtouch_login

        _old = settings.DEKIWIKI_ENDPOINT
        settings.DEKIWIKI_ENDPOINT = False
        resp = self.client.post(reverse('users.browserid_verify',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        settings.DEKIWIKI_ENDPOINT = _old

        eq_(302, resp.status_code)
        ok_('SUCCESS' in resp['Location'])

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

        ok_(not trap['was_called'])

    @mock_get_deki_user_by_email
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_changing_email(self, _verify_browserid):
        # just need to be authenticated, not necessarily BrowserID
        self.client.login(username='******', password='******')

        _verify_browserid.return_value = {'email': '*****@*****.**'}

        resp = self.client.post(reverse('users.browserid_change_email',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('profiles/testuser/edit' in resp['Location'])

        resp = self.client.get(reverse('devmo_profile_edit', locale='en-US',
                                       args=['testuser', ]))
        eq_(200, resp.status_code)
        doc = pq(resp.content)
        ok_('*****@*****.**' in doc.find('li#field_email').text())

    @mock_get_deki_user_by_email
    @mock_put_mindtouch_user
    @mock_mindtouch_login
    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_doesnt_steal_email(self, _verify_browserid):
        # just need to be authenticated, not necessarily BrowserID
        self.client.login(username='******', password='******')

        _verify_browserid.return_value = {'email': '*****@*****.**'}

        # doesn't change email if the new email already belongs to another user
        resp = self.client.post(reverse('users.browserid_change_email',
                                        locale='en-US'),
                                {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('change_email' in resp['Location'])

        resp = self.client.get(reverse('devmo_profile_edit', locale='en-US',
                                       args=['testuser', ]))
        eq_(200, resp.status_code)
        doc = pq(resp.content)
        ok_('*****@*****.**' in doc.find('li#field_email').text())
Пример #39
0
class BrowserIDTestCase(TestCase):
    fixtures = ['test_users.json']

    def setUp(self):
        # Ensure @ssl_required goes unenforced.
        settings.DEBUG = True
        # Set up some easily-testable redirects.
        settings.LOGIN_REDIRECT_URL = 'SUCCESS'
        settings.LOGIN_REDIRECT_URL_FAILURE = 'FAILURE'
        # BrowserID will squawk if this isn't set
        settings.SITE_URL = 'http://testserver'
        self.client = LocalizingClient()

    def test_invalid_post(self):
        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'))
        eq_(302, resp.status_code)
        ok_('FAILURE' in resp['Location'])

    @mock.patch('users.views._verify_browserid')
    def test_invalid_assertion(self, _verify_browserid):
        _verify_browserid.return_value = None

        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'),
            {'assertion': 'bad data'})
        eq_(302, resp.status_code)
        ok_('FAILURE' in resp['Location'])

    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_django_user(self, _verify_browserid):
        _verify_browserid.return_value = {'email': '*****@*****.**'}

        # Posting the fake assertion to browserid_verify should work, with the
        # actual verification method mocked out.
        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('SUCCESS' in resp['Location'])

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

    @mock.patch('users.views._verify_browserid')
    def test_explain_popup(self, _verify_browserid):
        _verify_browserid.return_value = {'email': '*****@*****.**'}
        resp = self.client.get(reverse('home', locale='en-US'))

        # Posting the fake assertion to browserid_verify should work, with the
        # actual verification method mocked out.
        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_('1', resp.cookies.get('browserid_explained').value)

        resp = self.client.get(reverse('users.logout'), locale='en-US')

        # even after logout, cookie should prevent the toggle
        resp = self.client.get(reverse('home', locale='en-US'))
        eq_('1', self.client.cookies.get('browserid_explained').value)

    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_new_account_creation(self,
                                                       _verify_browserid):
        new_username = '******'
        new_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': new_email}

        try:
            user = User.objects.get(email=new_email)
            ok_(False, "User for email should not yet exist")
        except User.DoesNotExist:
            pass

        # Sign in with a verified email, but with no existing account
        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)

        # This should be a redirect to the BrowserID registration page.
        redir_url = resp['Location']
        reg_url = reverse('users.browserid_register', locale='en-US')
        ok_(reg_url in redir_url)

        # And, as part of the redirect, the verified email address should be in
        # our session now.
        ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys())
        verified_email = self.client.session[SESSION_VERIFIED_EMAIL]
        eq_(new_email, verified_email)

        # Grab the redirect, assert that there's a create_user form present
        resp = self.client.get(redir_url)
        page = pq(resp.content)
        form = page.find('form#create_user')
        eq_(1, form.length)

        # There should be no error lists on first load
        eq_(0, page.find('.errorlist').length)

        # Submit the create_user form, with a chosen username
        resp = self.client.post(redir_url, {
            'username': '******',
            'action': 'register'
        })

        # The submission should result in a redirect to the session's redirect
        # value
        eq_(302, resp.status_code)
        redir_url = resp['Location']
        ok_('SUCCESS' in redir_url)

        # The session should look logged in, now.
        ok_('_auth_user_id' in self.client.session.keys())
        eq_('django_browserid.auth.BrowserIDBackend',
            self.client.session.get('_auth_user_backend', ''))

        # Ensure that the user was created, and with the submitted username and
        # verified email address
        try:
            user = User.objects.get(email=new_email)
            eq_(new_username, user.username)
            eq_(new_email, user.email)
        except User.DoesNotExist:
            ok_(False, "New user should have been created")

    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_with_existing_account_login(
            self, _verify_browserid):
        """ Removed the existing user form: we don't auth the password with
        MindTouch anymore """
        new_email = '*****@*****.**'
        _verify_browserid.return_value = {'email': new_email}

        try:
            User.objects.get(email=new_email)
            ok_(False, "User for email should not yet exist")
        except User.DoesNotExist:
            pass

        # Sign in with a verified email, but with no existing account
        resp = self.client.post(
            reverse('users.browserid_verify', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)

        # This should be a redirect to the BrowserID registration page.
        redir_url = resp['Location']
        reg_url = reverse('users.browserid_register', locale='en-US')
        ok_(reg_url in redir_url)

        # And, as part of the redirect, the verified email address should be in
        # our session now.
        ok_(SESSION_VERIFIED_EMAIL in self.client.session.keys())
        verified_email = self.client.session[SESSION_VERIFIED_EMAIL]
        eq_(new_email, verified_email)

        # Grab the redirect, assert that there's a create_user form present
        resp = self.client.get(redir_url)
        page = pq(resp.content)
        form = page.find('form#existing_user')
        eq_(0, form.length)

    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_changing_email(self, _verify_browserid):
        # just need to be authenticated, not necessarily BrowserID
        self.client.login(username='******', password='******')

        _verify_browserid.return_value = {'email': '*****@*****.**'}

        resp = self.client.post(
            reverse('users.browserid_change_email', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('profiles/testuser/edit' in resp['Location'])

        resp = self.client.get(
            reverse('devmo_profile_edit', locale='en-US', args=[
                'testuser',
            ]))
        eq_(200, resp.status_code)
        doc = pq(resp.content)
        ok_('*****@*****.**' in doc.find('li#field_email').text())

    @mock.patch('users.views._verify_browserid')
    def test_valid_assertion_doesnt_steal_email(self, _verify_browserid):
        # just need to be authenticated, not necessarily BrowserID
        self.client.login(username='******', password='******')

        _verify_browserid.return_value = {'email': '*****@*****.**'}

        # doesn't change email if the new email already belongs to another user
        resp = self.client.post(
            reverse('users.browserid_change_email', locale='en-US'),
            {'assertion': 'PRETENDTHISISVALID'})
        eq_(302, resp.status_code)
        ok_('change_email' in resp['Location'])

        resp = self.client.get(
            reverse('devmo_profile_edit', locale='en-US', args=[
                'testuser',
            ]))
        eq_(200, resp.status_code)
        doc = pq(resp.content)
        ok_('*****@*****.**' in doc.find('li#field_email').text())
Пример #40
0
class ProfileViewsTest(test_utils.TestCase):

    def setUp(self):
        self.client = LocalizingClient()

    def test_profile_view(self):
        """A user profile can be viewed"""
        (user, deki_user, profile) = self._create_profile()

        url = reverse('devmo.views.profile_view',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.user.username,
            doc.find('#profile-head.vcard .nickname').text())
        eq_(profile.fullname,
            doc.find('#profile-head.vcard .fn').text())
        eq_(profile.title,
            doc.find('#profile-head.vcard .title').text())
        eq_(profile.organization,
            doc.find('#profile-head.vcard .org').text())
        eq_(profile.location,
            doc.find('#profile-head.vcard .loc').text())
        eq_(profile.irc_nickname,
            doc.find('#profile-head.vcard .irc').text())
        eq_(profile.bio,
            doc.find('#profile-head.vcard .bio').text())

    @attr('current')
    def test_profile_edit(self):
        (user, deki_user, profile) = self._create_profile()

        url = reverse('devmo.views.profile_view',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(0, doc.find('#profile-head .edit .button').length)

        self.client.login(username=user.username, 
                password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_view',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        edit_button = doc.find('#profile-head .edit .button')
        eq_(1, edit_button.length)

        url = edit_button.attr('href')
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.fullname,
            doc.find('#profile-edit input[name="fullname"]').val())
        eq_(profile.title,
            doc.find('#profile-edit input[name="title"]').val())
        eq_(profile.organization,
            doc.find('#profile-edit input[name="organization"]').val())
        eq_(profile.location,
            doc.find('#profile-edit input[name="location"]').val())
        eq_(profile.irc_nickname,
            doc.find('#profile-edit input[name="irc_nickname"]').val())

        new_attrs = dict(
            email="*****@*****.**",
            fullname="Another Name",
            title="Another title",
            organization="Another org",
        )

        r = self.client.post(url, new_attrs, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)
        eq_(new_attrs['fullname'],
            doc.find('#profile-head .main .fn').text())
        eq_(new_attrs['title'],
            doc.find('#profile-head .info .title').text())
        eq_(new_attrs['organization'],
            doc.find('#profile-head .info .org').text())

        profile = UserProfile.objects.get(user__username=user.username)
        eq_(new_attrs['fullname'], profile.fullname)
        eq_(new_attrs['title'], profile.title)
        eq_(new_attrs['organization'], profile.organization)

    def test_profile_edit_websites(self):
        (user, deki_user, profile) = self._create_profile()

        self.client.login(username=user.username, 
                password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        test_sites = {
            u'website': u'http://example.com/',
            u'twitter': u'http://twitter.com/lmorchard',
            u'github': u'http://github.com/lmorchard',
            u'stackoverflow': u'http://stackoverflow.com/users/lmorchard',
        }

        # Scrape out the existing significant form field values.
        form = dict()
        for fn in ('email', 'fullname', 'title', 'organization', 'location',
                'irc_nickname', 'bio', 'interests'):
            form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val()

        # Fill out the form with websites.
        form.update(dict(('websites_%s' % k, v)
                    for k, v in test_sites.items()))

        # Submit the form, verify redirect to profile detail
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        # Verify the websites are saved in the profile.
        eq_(test_sites, p.websites)

        # Verify the saved websites appear in the editing form
        url = reverse('devmo.views.profile_edit',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        for k, v in test_sites.items():
            eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val())

        # Come up with some bad sites, either invalid URL or bad URL prefix
        bad_sites = {
            u'website': u'HAHAHA WHAT IS A WEBSITE',
            u'twitter': u'http://facebook.com/lmorchard',
            u'stackoverflow': u'http://overqueueblah.com/users/lmorchard',
        }
        form.update(dict(('websites_%s' % k, v)
                    for k, v in bad_sites.items()))

        # Submit the form, verify errors for all of the bad sites
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-edit').length)
        tmpl = '#profile-edit #elsewhere .%s .errorlist'
        for n in ('website', 'twitter', 'stackoverflow'):
            eq_(1, doc.find(tmpl % n).length)

    def test_profile_edit_interests(self):
        (user, deki_user, profile) = self._create_profile()

        self.client.login(username=user.username, 
                password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit',
                      args=(user.username,))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        form = dict()
        for fn in ('email', 'fullname', 'title', 'organization', 'location',
                'irc_nickname', 'bio', 'interests'):
            form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val()

        test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing']

        form['interests'] = ', '.join(test_tags)

        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [t.name.replace('profile:interest:', '')
                for t in p.tags.all_ns('profile:interest:')]
        result_tags.sort()
        test_tags.sort()
        eq_(test_tags, result_tags)

        test_expertise = ['css', 'canvas']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [t.name.replace('profile:expertise:', '')
                for t in p.tags.all_ns('profile:expertise')]
        result_tags.sort()
        test_expertise.sort()
        eq_(test_expertise, result_tags)

        # Now, try some expertise tags not covered in interests
        test_expertise = ['css', 'canvas', 'mobile', 'movies']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('.error #id_expertise').length)

    def _create_profile(self):
        """Create a user, deki_user, and a profile for a test account"""
        user = User.objects.create_user('tester23', '*****@*****.**',
                                        'trustno1')

        deki_user = DekiUser(id=0, username='******',
                             fullname='Tester Twentythree',
                             email='*****@*****.**',
                             gravatar='', profile_url=None)

        profile = UserProfile()
        profile.user = user
        profile.fullname = "Tester Twentythree"
        profile.title = "Spaceship Pilot"
        profile.organization = "UFO"
        profile.location = "Outer Space"
        profile.irc_nickname = "ircuser"
        profile.bio = "I am a freaky space alien."
        profile.save()

        return (user, deki_user, profile)

    def _break(self, url, r):
        logging.debug("URL  %s" % url)
        logging.debug("STAT %s" % r.status_code)
        logging.debug("HEAD %s" % r.items())
        logging.debug("CONT %s" % r.content)
        ok_(False)
Пример #41
0
class ProfileViewsTest(test_utils.TestCase):
    def setUp(self):
        self.client = LocalizingClient()

    def test_profile_view(self):
        """A user profile can be viewed"""
        (user, deki_user, profile) = self._create_profile()

        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.user.username,
            doc.find('#profile-head.vcard .nickname').text())
        eq_(profile.fullname, doc.find('#profile-head.vcard .fn').text())
        eq_(profile.title, doc.find('#profile-head.vcard .title').text())
        eq_(profile.organization, doc.find('#profile-head.vcard .org').text())
        eq_(profile.location, doc.find('#profile-head.vcard .loc').text())
        eq_(profile.irc_nickname, doc.find('#profile-head.vcard .irc').text())
        eq_(profile.bio, doc.find('#profile-head.vcard .bio').text())

    @attr('current')
    def test_profile_edit(self):
        (user, deki_user, profile) = self._create_profile()

        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(0, doc.find('#profile-head .edit .button').length)

        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_view', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        edit_button = doc.find('#profile-head .edit .button')
        eq_(1, edit_button.length)

        url = edit_button.attr('href')
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        eq_(profile.fullname,
            doc.find('#profile-edit input[name="fullname"]').val())
        eq_(profile.title, doc.find('#profile-edit input[name="title"]').val())
        eq_(profile.organization,
            doc.find('#profile-edit input[name="organization"]').val())
        eq_(profile.location,
            doc.find('#profile-edit input[name="location"]').val())
        eq_(profile.irc_nickname,
            doc.find('#profile-edit input[name="irc_nickname"]').val())

        new_attrs = dict(
            email="*****@*****.**",
            fullname="Another Name",
            title="Another title",
            organization="Another org",
        )

        r = self.client.post(url, new_attrs, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)
        eq_(new_attrs['fullname'], doc.find('#profile-head .main .fn').text())
        eq_(new_attrs['title'], doc.find('#profile-head .info .title').text())
        eq_(new_attrs['organization'],
            doc.find('#profile-head .info .org').text())

        profile = UserProfile.objects.get(user__username=user.username)
        eq_(new_attrs['fullname'], profile.fullname)
        eq_(new_attrs['title'], profile.title)
        eq_(new_attrs['organization'], profile.organization)

    def test_profile_edit_websites(self):
        (user, deki_user, profile) = self._create_profile()

        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        test_sites = {
            u'website': u'http://example.com/',
            u'twitter': u'http://twitter.com/lmorchard',
            u'github': u'http://github.com/lmorchard',
            u'stackoverflow': u'http://stackoverflow.com/users/lmorchard',
        }

        # Scrape out the existing significant form field values.
        form = dict()
        for fn in ('email', 'fullname', 'title', 'organization', 'location',
                   'irc_nickname', 'bio', 'interests'):
            form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val()

        # Fill out the form with websites.
        form.update(dict(
            ('websites_%s' % k, v) for k, v in test_sites.items()))

        # Submit the form, verify redirect to profile detail
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        # Verify the websites are saved in the profile.
        eq_(test_sites, p.websites)

        # Verify the saved websites appear in the editing form
        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)
        for k, v in test_sites.items():
            eq_(v, doc.find('#profile-edit *[name="websites_%s"]' % k).val())

        # Come up with some bad sites, either invalid URL or bad URL prefix
        bad_sites = {
            u'website': u'HAHAHA WHAT IS A WEBSITE',
            u'twitter': u'http://facebook.com/lmorchard',
            u'stackoverflow': u'http://overqueueblah.com/users/lmorchard',
        }
        form.update(dict(('websites_%s' % k, v) for k, v in bad_sites.items()))

        # Submit the form, verify errors for all of the bad sites
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)
        eq_(1, doc.find('#profile-edit').length)
        tmpl = '#profile-edit #elsewhere .%s .errorlist'
        for n in ('website', 'twitter', 'stackoverflow'):
            eq_(1, doc.find(tmpl % n).length)

    def test_profile_edit_interests(self):
        (user, deki_user, profile) = self._create_profile()

        self.client.login(username=user.username, password=TESTUSER_PASSWORD)

        url = reverse('devmo.views.profile_edit', args=(user.username, ))
        r = self.client.get(url, follow=True)
        doc = pq(r.content)

        form = dict()
        for fn in ('email', 'fullname', 'title', 'organization', 'location',
                   'irc_nickname', 'bio', 'interests'):
            form[fn] = doc.find('#profile-edit *[name="%s"]' % fn).val()

        test_tags = ['javascript', 'css', 'canvas', 'html', 'homebrewing']

        form['interests'] = ', '.join(test_tags)

        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [
            t.name.replace('profile:interest:', '')
            for t in p.tags.all_ns('profile:interest:')
        ]
        result_tags.sort()
        test_tags.sort()
        eq_(test_tags, result_tags)

        test_expertise = ['css', 'canvas']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('#profile-head').length)

        p = UserProfile.objects.get(user=user)

        result_tags = [
            t.name.replace('profile:expertise:', '')
            for t in p.tags.all_ns('profile:expertise')
        ]
        result_tags.sort()
        test_expertise.sort()
        eq_(test_expertise, result_tags)

        # Now, try some expertise tags not covered in interests
        test_expertise = ['css', 'canvas', 'mobile', 'movies']
        form['expertise'] = ', '.join(test_expertise)
        r = self.client.post(url, form, follow=True)
        doc = pq(r.content)

        eq_(1, doc.find('.error #id_expertise').length)

    def _create_profile(self):
        """Create a user, deki_user, and a profile for a test account"""
        user = User.objects.create_user('tester23', '*****@*****.**',
                                        'trustno1')

        deki_user = DekiUser(id=0,
                             username='******',
                             fullname='Tester Twentythree',
                             email='*****@*****.**',
                             gravatar='',
                             profile_url=None)

        profile = UserProfile()
        profile.user = user
        profile.fullname = "Tester Twentythree"
        profile.title = "Spaceship Pilot"
        profile.organization = "UFO"
        profile.location = "Outer Space"
        profile.irc_nickname = "ircuser"
        profile.bio = "I am a freaky space alien."
        profile.save()

        return (user, deki_user, profile)

    def _break(self, url, r):
        logging.debug("URL  %s" % url)
        logging.debug("STAT %s" % r.status_code)
        logging.debug("HEAD %s" % r.items())
        logging.debug("CONT %s" % r.content)
        ok_(False)