Example #1
0
    def test_delete_key(self):
        """User should be able to delete own keys, but no one else's"""
        self.client.login(username=self.username,
                          password=self.password)

        url = reverse('authkeys.delete', args=(self.key3.pk,),
                      locale='en-US')
        resp = self.client.get(url, follow=True)
        eq_(403, resp.status_code)

        resp = self.client.post(url, follow=False)
        ok_(403, resp.status_code)

        url = reverse('authkeys.delete', args=(self.key1.pk,),
                      locale='en-US')
        resp = self.client.get(url, follow=True)
        eq_(200, resp.status_code)

        page = pq(resp.content)
        eq_(self.key1.description, page.find('.key .description').text())

        resp = self.client.post(url, follow=False)
        ok_(302, resp.status_code)

        eq_(0, Key.objects.filter(pk=self.key1.pk).count())
Example #2
0
def _get_wiki_link(title, locale):
    """Checks the page exists, and returns its URL or the URL to create it.

    Return value is a dict: {'found': boolean, 'url': string}.
    found is False if the document does not exist.

    """
    # Prevent circular import. sumo is conceptually a utils apps and
    # shouldn't have import-time (or really, any, but that's not going
    # to happen) dependencies on client apps.
    from wiki.models import Document

    d = get_object_fallback(Document, locale=locale, title=title,
                            is_template=False)
    if d:
        # If the article redirects use its destination article
        while d.redirect_document():
            d = d.redirect_document()

        # The locale in the link urls should always match the current
        # document's locale even if the document/slug being linked to
        # is in the default locale.
        url = reverse('wiki.document', locale=locale, args=[d.slug])
        return {'found': True, 'url': url, 'text': d.title}

    # To avoid circular imports, wiki.models imports wiki_to_html
    from sumo.helpers import urlparams
    return {'found': False,
            'text': title,
            'url': urlparams(reverse('wiki.new_document', locale=locale),
                             title=title)}
Example #3
0
def _clean_next_url(request):
    if 'next' in request.POST:
        url = request.POST.get('next')
    elif 'next' in request.GET:
        url = request.GET.get('next')
    elif 'HTTP_REFERER' in request.META:
        url = request.META.get('HTTP_REFERER').decode('latin1', 'ignore')
    else:
        return None

    site = Site.objects.get_current()
    if not is_safe_url(url, site.domain):
        return None
    parsed_url = urlparse.urlparse(url)

    # Don't redirect right back to login, logout, register, or
    # change email pages
    locale, register_url = split_path(reverse(
        'users.browserid_register'))
    locale, change_email_url = split_path(reverse(
        'users.change_email'))
    LOOPING_NEXT_URLS = [settings.LOGIN_URL, settings.LOGOUT_URL,
                          register_url, change_email_url]
    for looping_url in LOOPING_NEXT_URLS:
        if looping_url in parsed_url.path:
            return None

    # TODO?HACK: can't use urllib.quote_plus because mod_rewrite quotes the
    # next url value already.
    url = url.replace(' ', '+')
    return url
Example #4
0
    def test_profile_edit(self, unsubscribe, subscribe, lookup_user):
        lookup_user.return_value = mock_lookup_user()
        subscribe.return_value = True
        unsubscribe.return_value = True
        profile = UserProfile.objects.get(user__username='******')
        user = profile.user
        url = reverse('users.profile', 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('users.profile', 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="profile-fullname"]').val())
        eq_(profile.title,
            doc.find('#profile-edit input[name="profile-title"]').val())
        eq_(profile.organization,
            doc.find('#profile-edit input[name="profile-organization"]').val())
        eq_(profile.location,
            doc.find('#profile-edit input[name="profile-location"]').val())
        eq_(profile.irc_nickname,
            doc.find('#profile-edit input[name="profile-irc_nickname"]').val())

        new_attrs = {
            'profile-email': '*****@*****.**',
            'profile-fullname': "Another Name",
            'profile-title': "Another title",
            'profile-organization': "Another org",
            'profile-country': "us",
            'profile-format': "html"
        }

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

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

        profile = UserProfile.objects.get(user__username=user.username)
        eq_(new_attrs['profile-fullname'], profile.fullname)
        eq_(new_attrs['profile-title'], profile.title)
        eq_(new_attrs['profile-organization'], profile.organization)
Example #5
0
def add_tag(request, question_id):
    """Add a (case-insensitive) tag to question.

    If the question already has the tag, do nothing.

    """
    # If somebody hits Return in the address bar after provoking an error from
    # the add form, nicely send them back to the question:
    if request.method == 'GET':
        return HttpResponseRedirect(
            reverse('questions.answers', args=[question_id]))

    try:
        question, canonical_name = _add_tag(request, question_id)
    except Tag.DoesNotExist:
        template_data = _answers_data(request, question_id)
        template_data['tag_adding_error'] = UNAPPROVED_TAG
        template_data['tag_adding_value'] = request.POST.get('tag-name', '')
        return jingo.render(request, 'questions/answers.html', template_data)

    if canonical_name:  # success
        question.clear_cached_tags()
        return HttpResponseRedirect(
            reverse('questions.answers', args=[question_id]))

    # No tag provided
    template_data = _answers_data(request, question_id)
    template_data['tag_adding_error'] = NO_TAG
    return jingo.render(request, 'questions/answers.html', template_data)
Example #6
0
 def test_redirect_to_contributor_dash(self):
     """Should redirect to Contributor Dash if the locale is the default"""
     response = self.client.get(reverse('dashboards.localization',
                                        locale='en-US'),
                                follow=True)
     self.assertRedirects(response, reverse('dashboards.contributors',
                                            locale='en-US'))
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
def context_dict(revision):
    """Return a dict that fills in the blanks in notification templates."""
    document = revision.document
    from_revision = revision.get_previous()
    to_revision = revision
    diff = revisions_unified_diff(from_revision, to_revision)

    compare_url = ""
    if from_revision:
        compare_url = reverse(
            "wiki.compare_revisions", args=[document.full_path], locale=document.locale
        ) + "?from=%s&to=%s" % (from_revision.id, to_revision.id)

    link_urls = {
        "compare_url": compare_url,
        "view_url": reverse("wiki.document", locale=document.locale, args=[document.slug]),
        "edit_url": reverse("wiki.edit_document", locale=document.locale, args=[document.slug]),
        "history_url": reverse("wiki.document_revisions", locale=document.locale, args=[document.slug]),
    }

    for name, url in link_urls.iteritems():
        url = add_utm(url, "Wiki Doc Edits")
        link_urls[name] = url

    context = {
        "document_title": document.title,
        "creator": revision.creator,
        "host": Site.objects.get_current().domain,
        "diff": diff,
    }
    context.update(link_urls)

    return context
Example #10
0
    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])
Example #11
0
    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())
Example #12
0
File: events.py Project: gerv/kuma
def context_dict(revision):
    """Return a dict that fills in the blanks in notification templates."""
    document = revision.document
    from_revision = revision.get_previous()
    to_revision = revision
    diff = revisions_unified_diff(from_revision, to_revision)

    compare_url = ''
    if from_revision:
        compare_url = (reverse('wiki.compare_revisions',
            args=[document.full_path], locale=document.locale)
            + '?from=%s&to=%s' % (from_revision.id, to_revision.id))

    return {
        'document_title': document.title,
        'creator': revision.creator,
        'host': Site.objects.get_current().domain,
        'compare_url': compare_url,
        'view_url': reverse('wiki.document',
                            locale=document.locale,
                            args=[document.slug]),
        'edit_url': reverse('wiki.edit_document',
                            locale=document.locale,
                            args=[document.slug]),
        'history_url': reverse('wiki.document_revisions',
                               locale=document.locale,
                               args=[document.slug]),

        'diff': diff
    }
Example #13
0
    def item_description(self, item):
        previous = item.get_previous()
        if previous is None:
            return '<p>Created by: %s</p>' % item.creator.username
        # TODO: put this in a jinja template if django syndication will let us
        by = '<p>Edited by: %s</p>' % item.creator.username
        comment = '<p>Comment: %s</p>' % item.comment
        diff = ("Diff:<blockquote>%s</blockquote>" % (
            diff_inline(previous.content, item.content)))

        diff = (diff.replace('<ins', '<ins style="background-color: #AAFFAA;"')
                .replace('<del', '<del style="background-color: #FFAAAA;"'))

        link_cell = '<td><a href="%s">%s</a></td>'
        view_cell = link_cell % (reverse('wiki.document',
                                         args=[item.document.full_path]),
                                 _('View Page'))
        edit_cell = link_cell % (reverse('wiki.edit_document',
                                         args=[item.document.full_path]),
                                 _('Edit Page'))
        compare_cell = link_cell % (reverse('wiki.compare_revisions',
                                         args=[item.document.full_path])
                                    + '?' +
                                    urllib.urlencode({'from': previous.id,
                                                      'to': item.id}),
                                 _('Show comparison'))
        history_cell = link_cell % (reverse('wiki.document_revisions',
                                         args=[item.document.full_path]),
                                 _('History'))
        links_table = '<table border="0" width="80%">'
        links_table = links_table + '<tr>%s%s%s%s</tr>' % (view_cell, edit_cell, compare_cell, history_cell)
        links_table = links_table + '</table>'
        description = "%s%s%s%s" % (by, comment, diff, links_table)
        return description
Example #14
0
    def test_forums_filter_updated(self):
        """Filter for updated date."""
        post_updated_ds = datetime(2010, 5, 3, 12, 00)

        thread1 = thread(title=u't1 audio', save=True)
        post(thread=thread1, created=post_updated_ds, save=True)

        thread2 = thread(title=u't2 audio', save=True)
        post(thread=thread2,
             created=(post_updated_ds + timedelta(days=2)),
             save=True)

        self.refresh()

        qs = {'a': 1, 'w': 4, 'format': 'json',
              'sortby': 1, 'updated_date': '05/04/2010'}

        qs['updated'] = constants.INTERVAL_BEFORE
        response = self.client.get(reverse('search'), qs)
        results = json.loads(response.content)['results']
        eq_([thread1.get_absolute_url()], [r['url'] for r in results])

        qs['updated'] = constants.INTERVAL_AFTER
        response = self.client.get(reverse('search'), qs)
        results = json.loads(response.content)['results']
        eq_([thread2.get_absolute_url()], [r['url'] for r in results])
Example #15
0
    def test_xss_file_attachment_title(self):
        title = '"><img src=x onerror=prompt(navigator.userAgent);>'
        # use view to create new attachment
        file_for_upload = make_test_file()
        post_data = {
            'title': title,
            'description': 'xss',
            'comment': 'xss',
            'file': file_for_upload,
        }
        self.client.login(username='******', password='******')
        resp = self.client.post(reverse('attachments.new_attachment'),
                                data=post_data)
        eq_(302, resp.status_code)

        # now stick it in/on a document
        attachment = Attachment.objects.get(title=title)
        rev = revision(content='<img src="%s" />' % attachment.get_file_url(),
                      save=True)

        # view it and verify markup is escaped
        response = self.client.get(reverse('wiki.edit_document', args=(rev.slug,),
                                    locale=settings.WIKI_DEFAULT_LANGUAGE))
        eq_(200, response.status_code)
        doc = pq(response.content)
        eq_('%s xss' % title,
            doc('#page-attachments-table .attachment-name-cell').text())
        ok_('&gt;&lt;img src=x onerror=prompt(navigator.userAgent);&gt;' in
            doc('#page-attachments-table .attachment-name-cell').html())
Example #16
0
    def test_advanced_search_questions_num_votes(self):
        """Tests advanced search for questions num_votes filter"""
        q = question(title=u'tags tags tags', save=True)

        # Add two question votes
        questionvote(question=q, save=True)
        questionvote(question=q, save=True)

        self.refresh()

        # Advanced search for questions with num_votes > 5. The above
        # question should be not in this set.
        response = self.client.get(reverse('search'), {
            'q': '', 'tags': 'desktop', 'w': '2', 'a': '1',
            'num_voted': 2, 'num_votes': 5,
            'format': 'json'
        })

        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(content['total'], 0)

        # Advanced search for questions with num_votes < 1. The above
        # question should be not in this set.
        response = self.client.get(reverse('search'), {
            'q': '', 'tags': 'desktop', 'w': '2', 'a': '1',
            'num_voted': 1, 'num_votes': 1,
            'format': 'json'
        })

        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(content['total'], 0)
Example #17
0
    def test_created(self):
        """Basic functionality of created filter."""
        created_ds = datetime(2010, 6, 19, 12, 00)

        # on 6/19/2010
        q1 = question(title=u'q1 audio', created=created_ds, save=True)
        q1.tags.add(u'desktop')
        ans = answer(question=q1, save=True)
        answervote(answer=ans, helpful=True, save=True)

        # on 6/21/2010
        q2 = question(title=u'q2 audio',
                      created=(created_ds + timedelta(days=2)),
                      save=True)
        q2.tags.add(u'desktop')
        ans = answer(question=q2, save=True)
        answervote(answer=ans, helpful=True, save=True)

        self.refresh()

        qs = {'a': 1, 'w': 2, 'format': 'json',
              'sortby': 2, 'created_date': '06/20/2010'}

        qs['created'] = constants.INTERVAL_BEFORE
        response = self.client.get(reverse('search'), qs)
        results = json.loads(response.content)['results']
        eq_([q1.get_absolute_url()], [r['url'] for r in results])

        qs['created'] = constants.INTERVAL_AFTER
        response = self.client.get(reverse('search'), qs)
        results = json.loads(response.content)['results']
        eq_([q2.get_absolute_url()], [r['url'] for r in results])
Example #18
0
 def test_persona_form_present(self):
     """
     When not authenticated, the Persona authentication components,
     with correct data attributes, are present in page contents,
     and the 'next' parameter is filled in.
     """
     all_docs_url = reverse('wiki.all_documents',
                            locale=settings.WIKI_DEFAULT_LANGUAGE)
     r = self.client.get(all_docs_url, follow=True)
     parsed = pq(r.content)
     request_info = '{"siteName": "%(siteName)s", "siteLogo": "%(siteLogo)s"}' % \
                    settings.SOCIALACCOUNT_PROVIDERS['persona']['REQUEST_PARAMETERS']
     stub_attrs = (
         ('data-csrf-token-url', reverse('persona_csrf_token')),
         ('data-request', request_info),
     )
     auth_attrs = (
         ('data-service', 'Persona'),
         ('data-next', all_docs_url),
     )
     stub_persona_form = parsed.find('#_persona_login')
     ok_(len(stub_persona_form) > 0)
     for stub_attr in stub_attrs:
         ok_(stub_persona_form.attr(stub_attr[0]))
         eq_(stub_attr[1], stub_persona_form.attr(stub_attr[0]))
     auth_persona_form = parsed.find('.launch-persona-login')
     ok_(len(auth_persona_form) > 0)
     for auth_attr in auth_attrs:
         ok_(auth_persona_form.attr(auth_attr[0]))
         eq_(auth_attr[1], auth_persona_form.attr(auth_attr[0]))
Example #19
0
    def test_advanced_search_sortby_documents_helpful(self):
        """Tests advanced search with a sortby_documents by helpful"""
        r1 = revision(is_approved=True, save=True)
        r2 = revision(is_approved=True, save=True)
        helpful_vote(revision=r2, helpful=True, save=True)

        # Note: We have to wipe and rebuild the index because new
        # helpful_votes don't update the index data.
        self.setup_indexes()
        self.reindex_and_refresh()

        # r2.document should come first with 1 vote.
        response = self.client.get(reverse('search'), {
            'w': '1', 'a': '1', 'sortby_documents': 'helpful',
            'format': 'json'})
        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(r2.document.title, content['results'][0]['title'])

        # Vote twice on r1, now it should come first.
        helpful_vote(revision=r1, helpful=True, save=True)
        helpful_vote(revision=r1, helpful=True, save=True)

        self.setup_indexes()
        self.reindex_and_refresh()

        response = self.client.get(reverse('search'), {
            'w': '1', 'a': '1', 'sortby_documents': 'helpful',
            'format': 'json'})
        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(r1.document.title, content['results'][0]['title'])
Example #20
0
    def test_new_user(self, get_current):
        get_current.return_value.domain = 'su.mo.com'
        response = self.client.post(reverse('users.register', locale='en-US'),
                                    {'username': '******',
                                     'email': '*****@*****.**',
                                     'password': '******',
                                     'password2': 'foobar22'}, follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(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/%s' % (u.id, key)) > 0

        # By default, users aren't added to any groups
        eq_(0, len(u.groups.all()))

        # Now try to log in
        u.is_active = True
        u.save()
        response = self.client.post(reverse('users.login', locale='en-US'),
                                    {'username': '******',
                                     'password': '******'}, follow=True)
        eq_(200, response.status_code)
        eq_('http://testserver/en-US/home', response.redirect_chain[0][0])
Example #21
0
def login(request, template):
    """Try to log the user in."""
    if request.method == 'GET' and not request.MOBILE:
        url = reverse('users.auth') + '?' + request.GET.urlencode()
        return HttpResponsePermanentRedirect(url)

    next_url = get_next_url(request) or reverse('home')
    form = handle_login(request)

    if request.user.is_authenticated():
        # Add a parameter so we know the user just logged in.
        # fpa =  "first page authed" or something.
        next_url = urlparams(next_url, fpa=1)
        res = HttpResponseRedirect(next_url)
        max_age = (None if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
                        else settings.SESSION_COOKIE_AGE)
        res.set_cookie(settings.SESSION_EXISTS_COOKIE,
                       '1',
                       secure=False,
                       max_age=max_age)
        return res

    if request.MOBILE:
        return jingo.render(request, template, {
            'form': form,
        })

    return user_auth(request, login_form=form)
Example #22
0
def _format_row_with_out_of_dateness(readout_locale, eng_slug, eng_title, slug,
                                    title, visits, significance, needs_review):
    """Format a row for a readout that has the traffic-light-style
    categorization of how seriously out of date a translation is."""
    if slug:  # A translation exists but may not be approved.
        locale = readout_locale
        status, view_name, status_class = SIGNIFICANCE_STATUSES.get(
            significance, REVIEW_STATUSES[needs_review])
        status_url = (reverse(view_name, args=[slug], locale=locale)
                      if view_name else '')
    else:
        slug = eng_slug
        title = eng_title
        locale = settings.WIKI_DEFAULT_LANGUAGE
        status = _(u'Translation Needed')
        # When calling the translate view, specify locale to translate to:
        status_url = reverse('wiki.translate', args=[slug],
                             locale=readout_locale)
        status_class = 'untranslated'

    return dict(title=title,
                url=reverse('wiki.document', args=[slug],
                            locale=locale),
                visits=visits,
                status=status,
                status_class=status_class,
                status_url=status_url)
Example #23
0
    def test_advanced_search_questions_num_votes(self):
        """Tests advanced search for questions num_votes filter"""
        q = question(title=u"tags tags tags", save=True)

        # Add two question votes
        questionvote(question=q, save=True)
        questionvote(question=q, save=True)

        self.refresh()

        # Advanced search for questions with num_votes > 5. The above
        # question should be not in this set.
        response = self.client.get(
            reverse("search"),
            {"q": "", "tags": "desktop", "w": "2", "a": "1", "num_voted": 2, "num_votes": 5, "format": "json"},
        )

        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(content["total"], 0)

        # Advanced search for questions with num_votes < 1. The above
        # question should be not in this set.
        response = self.client.get(
            reverse("search"),
            {"q": "", "tags": "desktop", "w": "2", "a": "1", "num_voted": 1, "num_votes": 1, "format": "json"},
        )

        eq_(200, response.status_code)

        content = json.loads(response.content)
        eq_(content["total"], 0)
Example #24
0
    def test_document_listing(self, flag_is_active):
        """Verify /products/<product slug>/<topic slug> renders articles."""
        flag_is_active.return_value = True

        # Create a topic and product.
        t1 = topic(save=True)
        t2 = topic(save=True)
        p = product(save=True)

        # Create 3 documents with the topic and product and one without.
        for i in range(3):
            doc = revision(is_approved=True, save=True).document
            doc.topics.add(t1)
            doc.products.add(p)
            if i == 1:  # Only one document with t2
                doc.topics.add(t2)

        doc = revision(is_approved=True, save=True).document

        self.refresh()

        # GET the page and verify the content.
        url = reverse('products.documents', args=[p.slug, t1.slug])
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)
        doc = pq(r.content)
        eq_(3, len(doc('#document-list > ul > li')))

        # GET the page with refine topic and verify the content.
        url = reverse('products.documents', args=[p.slug, t1.slug])
        url = urlparams(url, refine=t2.slug)
        r = self.client.get(url, follow=True)
        eq_(200, r.status_code)
        doc = pq(r.content)
        eq_(1, len(doc('#document-list > ul > li')))
Example #25
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'))
Example #26
0
    def test_needs_change(self):
        """Test setting and unsetting the needs change flag"""
        # Create a new document and edit it, setting needs_change.
        comment = 'Please update for Firefix.next'
        doc = revision(save=True).document
        data = new_document_data()
        data.update({'needs_change': True,
                     'needs_change_comment': comment,
                     'form': 'doc'})

        # Verify that needs_change can't be set if the user doesn't have
        # the permission.
        self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data)
        doc = Document.uncached.get(pk=doc.pk)
        assert not doc.needs_change
        assert not doc.needs_change_comment

        # Give the user permission, now it should work.
        add_permission(self.u, Document, 'edit_needs_change')
        self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data)
        doc = Document.uncached.get(pk=doc.pk)
        assert doc.needs_change
        eq_(comment, doc.needs_change_comment)

        # Clear out needs_change.
        data.update({'needs_change': False,
                     'needs_change_comment': comment})
        self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data)
        doc = Document.uncached.get(pk=doc.pk)
        assert not doc.needs_change
        eq_('', doc.needs_change_comment)
Example #27
0
def devmo_url(context, path):
    """ Create a URL pointing to devmo.
        Look for a wiki page in the current locale, or default to given path
    """
    if hasattr(context["request"], "locale"):
        locale = context["request"].locale
    else:
        locale = settings.WIKI_DEFAULT_LANGUAGE
    try:
        url = cache.get("devmo_url:%s_%s" % (locale, path))
    except:
        return path
    if not url:
        url = reverse("wiki.document", locale=settings.WIKI_DEFAULT_LANGUAGE, args=[path])
        if locale != settings.WIKI_DEFAULT_LANGUAGE:
            try:
                parent = Document.objects.get(locale=settings.WIKI_DEFAULT_LANGUAGE, slug=path)
                """ # TODO: redirect_document is coupled to doc view
                follow redirects vs. update devmo_url calls
                
                target = parent.redirect_document()
                if target:
                parent = target
                """
                child = Document.objects.get(locale=locale, parent=parent)
                url = reverse("wiki.document", locale=locale, args=[child.slug])
            except Document.DoesNotExist:
                pass
        cache.set("devmo_url:%s_%s" % (locale, path), url)
    return url
Example #28
0
    def test_created(self):
        """Basic functionality of created filter."""
        created_ds = datetime(2010, 6, 19, 12, 00)

        # on 6/19/2010
        q1 = question(title=u"q1 audio", created=created_ds, save=True)
        q1.tags.add(u"desktop")
        ans = answer(question=q1, save=True)
        answervote(answer=ans, helpful=True, save=True)

        # on 6/21/2010
        q2 = question(title=u"q2 audio", created=(created_ds + timedelta(days=2)), save=True)
        q2.tags.add(u"desktop")
        ans = answer(question=q2, save=True)
        answervote(answer=ans, helpful=True, save=True)

        self.refresh()

        qs = {"a": 1, "w": 2, "format": "json", "sortby": 2, "created_date": "06/20/2010"}

        qs["created"] = constants.INTERVAL_BEFORE
        response = self.client.get(reverse("search"), qs)
        results = json.loads(response.content)["results"]
        eq_([q1.get_absolute_url()], [r["url"] for r in results])

        qs["created"] = constants.INTERVAL_AFTER
        response = self.client.get(reverse("search"), qs)
        results = json.loads(response.content)["results"]
        eq_([q2.get_absolute_url()], [r["url"] for r in results])
Example #29
0
 def test_my_profile_edit(self):
     u = User.objects.get(username='******')
     self.client.login(username=u.username, password=TESTUSER_PASSWORD)
     resp = self.client.get(reverse('users.my_profile_edit'))
     eq_(302, resp.status_code)
     ok_(reverse('users.profile_edit', args=(u.username,)) in
         resp['Location'])
Example #30
0
    def test_new_contributor(self, get_current):
        """Verify that interested contributors are added to group."""
        get_current.return_value.domain = 'su.mo.com'
        group_name = 'Registered as contributor'
        group(name=group_name, save=True)
        data = {
            'username': '******',
            'email': '*****@*****.**',
            'password': '******',
            'password2': 'foobar22',
            'interested': 'yes'}
        response = self.client.post(reverse('users.register', locale='en-US'),
                                    data, follow=True)
        eq_(200, response.status_code)
        u = User.objects.get(username='******')
        eq_(group_name, u.groups.all()[0].name)

        # Activate user and verify email is sent.
        key = RegistrationProfile.objects.all()[0].activation_key
        url = reverse('users.activate', args=[u.id, key])
        response = self.client.get(url, follow=True)
        eq_(200, response.status_code)
        eq_(2, len(mail.outbox))
        assert mail.outbox[1].subject.find('Welcome to') == 0
        assert u.username in mail.outbox[1].body
Example #31
0
 def test_redirect_permanent(self):
     resp = redirect_to(self.rf.get('/'), url='home')
     assert isinstance(resp, HttpResponsePermanentRedirect)
     eq_(reverse('home'), resp['location'])
Example #32
0
 def test_top_text(self):
     response = self.client.get(reverse('home.mobile'), follow=True)
     self.assertContains(response, 'Firefox for Mobile')
Example #33
0
class UnreadyForLocalizationReadout(Readout):
    """Articles which have approved but unready revisions newer than their
    latest ready-for-l10n ones"""
    title = _lazy(u'Changes Not Ready For Localization')
    description = _lazy(u'Articles which have approved revisions newer than '
                        'the latest ready-for-localization one')
    # No short_title; the Contributors dash lacks an Overview readout
    details_link_text = _lazy(u'All articles with changes not ready for '
                              'localization...')
    slug = 'unready'
    column4_label = _lazy(u'Approved')

    def _query_and_params(self, max):
        # Filter by product if specified.
        if self.product:
            extra_joins = PRODUCT_FILTER
            params = (LAST_30_DAYS, self.product.id,
                      settings.WIKI_DEFAULT_LANGUAGE, TYPO_SIGNIFICANCE)
        else:
            extra_joins = ''
            params = (LAST_30_DAYS, settings.WIKI_DEFAULT_LANGUAGE,
                      TYPO_SIGNIFICANCE)

        query = (
            'SELECT engdoc.slug, engdoc.title, '
            'MAX(wiki_revision.reviewed) maxreviewed, '
            'visits.visits '
            'FROM wiki_document engdoc '
            'INNER JOIN wiki_revision ON '
            'engdoc.id=wiki_revision.document_id '
            'LEFT JOIN dashboards_wikidocumentvisits visits ON '
            'engdoc.id=visits.document_id AND '
            'visits.period=%s ' + extra_joins +
            'WHERE engdoc.locale=%s '  # shouldn't be necessary
            'AND NOT engdoc.is_archived '
            'AND engdoc.is_localizable '
            'AND (engdoc.current_revision_id>'
            'engdoc.latest_localizable_revision_id OR '
            'engdoc.latest_localizable_revision_id IS NULL) '
            # When picking the max(reviewed) date, consider only revisions that
            # are ripe to be marked Ready:
            'AND wiki_revision.is_approved '
            'AND NOT wiki_revision.is_ready_for_localization '
            'AND (wiki_revision.significance>%s OR '
            'wiki_revision.significance IS NULL) '  # initial revision
            # An optimization: minimize rows before max():
            'AND (wiki_revision.id>'
            'engdoc.latest_localizable_revision_id OR '
            'engdoc.latest_localizable_revision_id IS NULL) '
            'GROUP BY engdoc.id ' + self._order_clause() +
            self._limit_clause(max))

        return query, params

    def _order_clause(self):
        # Put the most recently approved articles first, as those are the most
        # recent to have transitioned onto this dashboard or to change which
        # revision causes them to be on this dashboard.
        return ('ORDER BY maxreviewed DESC' if self.mode == MOST_RECENT else
                'ORDER BY visits.visits DESC, engdoc.title ASC')

    def _format_row(self, (slug, title, reviewed, visits)):
        return dict(title=title,
                    url=reverse('wiki.document_revisions',
                                args=[slug],
                                locale=settings.WIKI_DEFAULT_LANGUAGE),
                    visits=visits,
                    updated=reviewed)
Example #34
0
class UnreviewedReadout(Readout):
    # L10n: Not just changes to translations but also unreviewed changes to
    # docs in this locale that are not translations
    title = _lazy(u'Unreviewed Changes')

    short_title = _lazy(u'Unreviewed', 'document')
    details_link_text = _lazy(u'All articles requiring review...')
    slug = 'unreviewed'
    column4_label = _lazy(u'Changed')

    def _query_and_params(self, max):
        english_id = ('id' if self.locale == settings.WIKI_DEFAULT_LANGUAGE
                      else 'parent_id')

        # Filter by product if specified.
        if self.product:
            extra_joins = ('INNER JOIN wiki_document_products docprod ON '
                           'docprod.document_id=wiki_document.' + english_id +
                           ' '
                           'AND docprod.product_id=%s ')
            params = (LAST_30_DAYS, self.product.id, self.locale)
        else:
            extra_joins = ''
            params = (LAST_30_DAYS, self.locale)

        query = (
            'SELECT wiki_document.slug, wiki_document.title, '
            'MAX(wiki_revision.created) maxcreated, '
            'GROUP_CONCAT(DISTINCT auth_user.username '
            "ORDER BY wiki_revision.id SEPARATOR ', '), "
            'dashboards_wikidocumentvisits.visits '
            'FROM wiki_document '
            'INNER JOIN wiki_revision ON '
            'wiki_document.id=wiki_revision.document_id '
            'INNER JOIN auth_user ON wiki_revision.creator_id=auth_user.id '
            'LEFT JOIN dashboards_wikidocumentvisits ON '
            'wiki_document.' + english_id +
            '=dashboards_wikidocumentvisits.document_id AND '
            'dashboards_wikidocumentvisits.period=%s ' + extra_joins +
            'WHERE wiki_revision.reviewed IS NULL '
            'AND (wiki_document.current_revision_id IS NULL OR '
            'wiki_revision.id>wiki_document.current_revision_id) '
            'AND wiki_document.locale=%s AND NOT wiki_document.is_archived '
            'GROUP BY wiki_document.id ' + self._order_clause() +
            self._limit_clause(max))

        return query, params

    def _order_clause(self):
        return ('ORDER BY maxcreated DESC' if self.mode == MOST_RECENT else
                'ORDER BY dashboards_wikidocumentvisits.visits DESC, '
                'wiki_document.title ASC')

    def _format_row(self, (slug, title, changed, users, visits)):
        return dict(title=title,
                    url=reverse('wiki.document_revisions',
                                args=[slug],
                                locale=self.locale),
                    visits=visits,
                    updated=changed,
                    users=users)
Example #35
0
class OutOfDateReadout(Readout):
    title = _lazy(u'Immediate Updates Needed')
    description = _lazy(
        u'This indicates a major edit which changes the content of the article'
        ' enough to hurt the value of the localization. Until it is updated, '
        'the localized page will warn users that it may be outdated. You '
        'should update these articles as soon as possible.')
    short_title = _lazy(u'Immediate Updates Needed')
    details_link_text = _lazy(u'All translations needing immediate updates...')
    slug = 'out-of-date'
    column4_label = _lazy(u'Out of date since')

    # To show up in this readout, an article's revision since the last
    # approved translation must have a maximum significance equal to this
    # value:
    _max_significance = MAJOR_SIGNIFICANCE

    def _query_and_params(self, max):
        # Filter by product if specified.
        if self.product:
            extra_joins = PRODUCT_FILTER
            params = (MEDIUM_SIGNIFICANCE, self._max_significance,
                      LAST_30_DAYS, self.product.id, self.locale)
        else:
            extra_joins = ''
            params = (MEDIUM_SIGNIFICANCE, self._max_significance,
                      LAST_30_DAYS, self.locale)

        # At the moment, the "Out of Date Since" column shows the time since
        # the translation was out of date at a MEDIUM level of severity or
        # higher. We could arguably knock this up to MAJOR, but technically it
        # is out of date when the original gets anything more than typo
        # corrections.

        # TODO: This is wrong because it uses the reviewed date to calculate
        # "Out of date since", instead of using the ready for l10n date.
        # To fix it is pretty hairy though. What a query!!!
        query = (
            'SELECT transdoc.slug, transdoc.title, engrev.reviewed, '
            'dashboards_wikidocumentvisits.visits '
            'FROM wiki_document transdoc '
            'INNER JOIN wiki_document engdoc ON transdoc.parent_id=engdoc.id '
            'INNER JOIN wiki_revision engrev ON engrev.id='
            # The oldest English rev to have an approved, ready-for-
            # localization level-30 change since the translated doc had an
            # approved rev based on it. NULL if there is none:
            '(SELECT min(id) FROM wiki_revision '
            # Narrow engrev rows to those representing revision of parent
            # doc:
            'WHERE wiki_revision.document_id=transdoc.parent_id '
            # For the purposes of computing the "Out of Date Since" column,
            # the revision that threw the translation out of date had
            # better be more recent than the one the current translation is
            # based on:
            'AND wiki_revision.id>'
            '(SELECT based_on_id FROM wiki_revision basedonrev '
            'WHERE basedonrev.id=transdoc.current_revision_id) '
            'AND wiki_revision.significance>=%s '
            'AND %s='
            # Completely filter out outer selections where 30 is not the
            # max signif of approved English revisions since trans was last
            # approved. Other maxes will be shown by other readouts.
            # Optimize: try "30 IN" if MySQL's statistics gatherer is
            # stupid/nonexistent; the inner query should be able to bail
            # out early. [Ed: No effect on EXPLAIN on admittedly light test
            # corpus.]
            '(SELECT MAX(engsince.significance) '
            'FROM wiki_revision engsince '
            'WHERE engsince.document_id=transdoc.parent_id '
            # Assumes that any approved revision became the current
            # revision at some point: we don't let the user go back and
            # approve revisions older than the latest approved one.
            'AND engsince.is_approved '
            # Consider revisions between the one the last translation
            # was based on and the latest ready-for-l10n one.
            'AND engsince.id>'
            # The English revision the current translation's based on:
            '(SELECT based_on_id FROM wiki_revision basedonrev '
            'WHERE basedonrev.id=transdoc.current_revision_id) '
            'AND engsince.id<=engdoc.latest_localizable_revision_id'
            ')'
            ') '
            # Join up the visits table for stats:
            'LEFT JOIN dashboards_wikidocumentvisits ON '
            'engrev.document_id=dashboards_wikidocumentvisits.document_id '
            'AND dashboards_wikidocumentvisits.period=%s ' + extra_joins +
            # We needn't check is_localizable, since the models ensure every
            # document with translations has is_localizable set.
            'WHERE transdoc.locale=%s AND NOT transdoc.is_archived AND '
            'transdoc.category in (10, 20, 60) ' + self._order_clause() +
            self._limit_clause(max))

        return query, params

    def _order_clause(self):
        return ('ORDER BY engrev.reviewed DESC' if self.mode == MOST_RECENT
                else 'ORDER BY dashboards_wikidocumentvisits.visits DESC, '
                'transdoc.title ASC')

    def _format_row(self, (slug, title, reviewed, visits)):
        return dict(title=title,
                    url=reverse('wiki.edit_document', args=[slug]),
                    visits=visits,
                    updated=reviewed)
Example #36
0
 def setUp(self):
     self.user = user()
     self.user.save()
     self.profile = profile(user=self.user)
     self.url = reverse('users.profile', args=[self.user.pk],
                        locale='en-US')
Example #37
0
 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'])
Example #38
0
    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"]')
Example #39
0
 def test_submit_loggedout(self):
     r = self.client.get(reverse('demos_submit'))
     choices = pq(r.content)('p.choices a[href*="signin"]')
     eq_(choices.length, 1)
Example #40
0
 def test_search_view(self):
     try:
         self.client.get(reverse('demos_search'))
     except:
         self.fail("Search should not ISE.")
Example #41
0
 def test_anonymous_user(self):
     """Checks the locale dashboard doesn't load for an anonymous user."""
     response = self.client.get(
         reverse('dashboards.group', args=[self.g.pk], locale='en-US'))
     eq_(302, response.status_code)
     assert '/users/login' in response['location']
Example #42
0
 def test_submit_loggedin(self):
     r = self.client.get(reverse('demos_submit'))
     assert pq(r.content)('form#demo-submit')
Example #43
0
    def test_active(self):
        """Active announcement shows."""
        announcement(creator=self.creator).save()

        response = self.client.get(reverse('dashboards.review'), follow=True)
        self.assertContains(response, 'stardate 43124.5')
Example #44
0
def get_user_url(user):
    from sumo.urlresolvers import reverse
    return reverse('users.profile', args=[user.username])
Example #45
0
 def test_gallery_invalid_type(self):
     url = reverse('gallery.gallery', args=['foo'])
     response = self.client.get(url, follow=True)
     eq_(404, response.status_code)
Example #46
0
 def test_no_announcements(self):
     """Template renders with no announcements."""
     response = self.client.get(reverse('dashboards.review'), follow=True)
     doc = pq(response.content)
     assert not len(doc('ol.announcements'))
Example #47
0
 def test_search_description(self):
     url = reverse('gallery.search', args=['image'])
     response = self.client.get(url, {'q': 'migrated'}, follow=True)
     doc = pq(response.content)
     eq_(5, len(doc('#media-list li')))
Example #48
0
 def test_redirect(self):
     """/gallery redirects to /gallery/images"""
     response = self.client.get(reverse('gallery.home', locale='en-US'),
                                follow=False)
     eq_(301, response.status_code)
     eq_('http://testserver/en-US/gallery/images', response['location'])
Example #49
0
 def test_image_search(self):
     url = reverse('gallery.search', args=['image'])
     response = self.client.get(url, {'q': 'quicktime'}, follow=True)
     doc = pq(response.content)
     eq_(1, len(doc('#media-list li')))
Example #50
0
 def test_search_nonexistent(self):
     url = reverse('gallery.search', args=['foo'])
     response = self.client.get(url, {'q': 'foo'}, follow=True)
     eq_(404, response.status_code)
Example #51
0
def translate(request, document_slug, revision_id=None):
    """Create a new translation of a wiki document.

    * document_slug is for the default locale
    * translation is to the request locale

    """
    # TODO: Refactor this view into two views? (new, edit)
    # That might help reduce the headache-inducing branchiness.
    parent_doc = get_object_or_404(Document,
                                   locale=settings.WIKI_DEFAULT_LANGUAGE,
                                   slug=document_slug)
    user = request.user

    if settings.WIKI_DEFAULT_LANGUAGE == request.locale:
        # Don't translate to the default language.
        return HttpResponseRedirect(
            reverse('wiki.edit_document',
                    locale=settings.WIKI_DEFAULT_LANGUAGE,
                    args=[parent_doc.slug]))

    if not parent_doc.is_localizable:
        message = _lazy(u'You cannot translate this document.')
        return jingo.render(request,
                            'handlers/400.html', {'message': message},
                            status=400)

    based_on_rev = parent_doc.localizable_or_latest_revision(
        include_rejected=True)

    disclose_description = bool(request.GET.get('opendescription'))

    try:
        doc = parent_doc.translations.get(locale=request.locale)
    except Document.DoesNotExist:
        doc = None
        disclose_description = True

    user_has_doc_perm = ((not doc) or (doc and doc.allows_editing_by(user)))
    user_has_rev_perm = ((not doc) or (doc and doc.allows_revision_by(user)))
    if not user_has_doc_perm and not user_has_rev_perm:
        # User has no perms, bye.
        raise PermissionDenied

    doc_form = rev_form = None
    base_rev = None

    if user_has_doc_perm:
        doc_initial = _document_form_initial(doc) if doc else None
        doc_form = DocumentForm(
            initial=doc_initial,
            can_create_tags=user.has_perm('taggit.add_tag'))
    if user_has_rev_perm:
        initial = {'based_on': based_on_rev.id, 'comment': ''}
        if revision_id:
            base_rev = Revision.objects.get(pk=revision_id)
            initial.update(content=base_rev.content,
                           summary=base_rev.summary,
                           keywords=base_rev.keywords)
        elif not doc:
            initial.update(content=based_on_rev.content,
                           summary=based_on_rev.summary,
                           keywords=based_on_rev.keywords)

        # Get a revision of the translation to plonk into the page as a
        # starting point. Since translations are never "ready for
        # localization", this will first try to find an approved revision, then
        # an unrejected one, then give up.
        instance = doc and doc.localizable_or_latest_revision()

        rev_form = RevisionForm(instance=instance, initial=initial)
        base_rev = base_rev or instance

    if request.method == 'POST':
        which_form = request.POST.get('form', 'both')
        doc_form_invalid = False

        if user_has_doc_perm and which_form in ['doc', 'both']:
            disclose_description = True
            post_data = request.POST.copy()
            post_data.update({'locale': request.locale})
            doc_form = DocumentForm(
                post_data,
                instance=doc,
                can_create_tags=user.has_perm('taggit.add_tag'))
            doc_form.instance.locale = request.locale
            doc_form.instance.parent = parent_doc
            if which_form == 'both':
                rev_form = RevisionForm(request.POST)

            # If we are submitting the whole form, we need to check that
            # the Revision is valid before saving the Document.
            if doc_form.is_valid() and (which_form == 'doc'
                                        or rev_form.is_valid()):
                doc = doc_form.save(parent_doc)

                # Possibly schedule a rebuild.
                _maybe_schedule_rebuild(doc_form)

                if which_form == 'doc':
                    url = urlparams(reverse('wiki.edit_document',
                                            args=[doc.slug]),
                                    opendescription=1)
                    return HttpResponseRedirect(url)

                doc_slug = doc_form.cleaned_data['slug']
            else:
                doc_form_invalid = True
        else:
            doc_slug = doc.slug

        if doc and user_has_rev_perm and which_form in ['rev', 'both']:
            rev_form = RevisionForm(request.POST)
            rev_form.instance.document = doc  # for rev_form.clean()
            if rev_form.is_valid() and not doc_form_invalid:
                _save_rev_and_notify(rev_form, request.user, doc)
                url = reverse('wiki.document_revisions', args=[doc_slug])
                return HttpResponseRedirect(url)

    show_revision_warning = _show_revision_warning(doc, base_rev)

    return jingo.render(
        request, 'wiki/translate.html', {
            'parent': parent_doc,
            'document': doc,
            'document_form': doc_form,
            'revision_form': rev_form,
            'locale': request.locale,
            'based_on': based_on_rev,
            'disclose_description': disclose_description,
            'show_revision_warning': show_revision_warning
        })
Example #52
0
 def test_video_search(self):
     url = reverse('gallery.search', args=['video'])
     response = self.client.get(url, {'q': '1802'}, follow=True)
     doc = pq(response.content)
     eq_(1, len(doc('#media-list li')))
Example #53
0
def edit_document(request, document_slug, revision_id=None):
    """Create a new revision of a wiki document, or edit document metadata."""
    doc = get_object_or_404(Document,
                            locale=request.locale,
                            slug=document_slug)
    user = request.user

    # If this document has a parent, then the edit is handled by the
    # translate view. Pass it on.
    if doc.parent:
        return translate(request, doc.parent.slug, revision_id)
    if revision_id:
        rev = get_object_or_404(Revision, pk=revision_id, document=doc)
    else:
        rev = doc.current_revision or doc.revisions.order_by(
            '-created', '-id')[0]

    disclose_description = bool(request.GET.get('opendescription'))
    doc_form = rev_form = None
    if doc.allows_revision_by(user):
        rev_form = RevisionForm(instance=rev,
                                initial={
                                    'based_on': rev.id,
                                    'comment': ''
                                })
    if doc.allows_editing_by(user):
        doc_form = DocumentForm(
            initial=_document_form_initial(doc),
            can_create_tags=user.has_perm('taggit.add_tag'),
            can_archive=user.has_perm('wiki.archive_document'))

    if request.method == 'GET':
        if not (rev_form or doc_form):
            # You can't do anything on this page, so get lost.
            raise PermissionDenied
    else:  # POST
        # Comparing against localized names for the Save button bothers me, so
        # I embedded a hidden input:
        which_form = request.POST.get('form')

        if which_form == 'doc':
            if doc.allows_editing_by(user):
                post_data = request.POST.copy()
                post_data.update({'locale': request.locale})
                doc_form = DocumentForm(
                    post_data,
                    instance=doc,
                    can_create_tags=user.has_perm('taggit.add_tag'),
                    can_archive=user.has_perm('wiki.archive_document'))
                if doc_form.is_valid():
                    # Get the possibly new slug for the imminent redirection:
                    doc = doc_form.save(None)

                    # Do we need to rebuild the KB?
                    _maybe_schedule_rebuild(doc_form)

                    return HttpResponseRedirect(
                        urlparams(reverse('wiki.edit_document',
                                          args=[doc.slug]),
                                  opendescription=1))
                disclose_description = True
            else:
                raise PermissionDenied
        elif which_form == 'rev':
            if doc.allows_revision_by(user):
                rev_form = RevisionForm(request.POST)
                rev_form.instance.document = doc  # for rev_form.clean()
                if rev_form.is_valid():
                    _save_rev_and_notify(rev_form, user, doc)
                    if 'notify-future-changes' in request.POST:
                        EditDocumentEvent.notify(request.user, doc)
                    return HttpResponseRedirect(
                        reverse('wiki.document_revisions',
                                args=[document_slug]))
            else:
                raise PermissionDenied

    show_revision_warning = _show_revision_warning(doc, rev)

    return jingo.render(
        request, 'wiki/edit_document.html', {
            'revision_form': rev_form,
            'document_form': doc_form,
            'disclose_description': disclose_description,
            'document': doc,
            'show_revision_warning': show_revision_warning
        })
Example #54
0
 def setUp(self):
     url_ = reverse('forums.threads', args=[u'testslug'])
     self.context = {'request': test_utils.RequestFactory().get(url_)}
     self.context['request'].locale = u'en-US'
Example #55
0
 def test_fallback_with_query_params(self):
     """The query parameters should be passed along to the redirect."""
     en_doc, de_doc = self._create_en_and_de_docs()
     url = reverse('wiki.document', args=[en_doc.slug], locale='de')
     response = self.client.get(url + '?x=y&x=z', follow=True)
     self.assertRedirects(response, de_doc.get_absolute_url() + '?x=y&x=z')
Example #56
0
def review_revision(request, document_slug, revision_id):
    """Review a revision of a wiki document."""
    rev = get_object_or_404(Revision,
                            pk=revision_id,
                            document__slug=document_slug)
    doc = rev.document
    form = ReviewForm(
        initial={
            'needs_change': doc.needs_change,
            'needs_change_comment': doc.needs_change_comment
        })

    # Don't ask significance if this doc is a translation or if it has no
    # former approved versions:
    should_ask_significance = not doc.parent and doc.current_revision

    based_on_revs = doc.revisions.all()
    last_approved_date = getattr(doc.current_revision, 'created',
                                 datetime.fromordinal(1))
    based_on_revs = based_on_revs.filter(created__gt=last_approved_date)
    recent_contributors = based_on_revs.values_list('creator__username',
                                                    flat=True)

    if request.method == 'POST':
        form = ReviewForm(request.POST)
        if form.is_valid() and not rev.reviewed:
            # Don't allow revisions to be reviewed twice
            rev.is_approved = 'approve' in request.POST
            rev.reviewer = request.user
            rev.reviewed = datetime.now()
            if should_ask_significance and form.cleaned_data['significance']:
                rev.significance = form.cleaned_data['significance']

            # If document is localizable and revision was approved and
            # user has permission, set the is_ready_for_localization value.
            if (doc.is_localizable and rev.is_approved
                    and request.user.has_perm('wiki.mark_ready_for_l10n')):
                rev.is_ready_for_localization = form.cleaned_data[
                    'is_ready_for_localization']

            rev.save()

            # Update the needs change bit (if approved, default language and
            # user has permission).
            if (doc.locale == settings.WIKI_DEFAULT_LANGUAGE
                    and doc.allows_editing_by(request.user)
                    and rev.is_approved):
                doc.needs_change = form.cleaned_data['needs_change']
                doc.needs_change_comment = \
                    form.cleaned_data['needs_change_comment']
                doc.save()

            # Send notifications of approvedness and readiness:
            if rev.is_ready_for_localization or rev.is_approved:
                events = [ApproveRevisionInLocaleEvent(rev)]
                if rev.is_ready_for_localization:
                    events.append(ReadyRevisionEvent(rev))
                ApprovedOrReadyUnion(*events).fire(
                    exclude=[rev.creator, request.user])

            # Send an email (not really a "notification" in the sense that
            # there's a Watch table entry) to revision creator.
            msg = form.cleaned_data['comment']
            send_reviewed_notification.delay(rev, doc, msg)
            send_contributor_notification(based_on_revs, rev, doc, msg)

            # Schedule KB rebuild?
            statsd.incr('wiki.review')
            schedule_rebuild_kb()

            return HttpResponseRedirect(
                reverse('wiki.document_revisions', args=[document_slug]))

    if doc.parent:  # A translation
        # For diffing the based_on revision against, to help the user see if he
        # translated all the recent changes:
        parent_revision = doc.parent.localizable_or_latest_revision()
        template = 'wiki/review_translation.html'
    else:
        parent_revision = None
        template = 'wiki/review_revision.html'

    data = {
        'revision': rev,
        'document': doc,
        'form': form,
        'parent_revision': parent_revision,
        'recent_contributors': list(recent_contributors),
        'should_ask_significance': should_ask_significance
    }
    data.update(SHOWFOR_DATA)
    return jingo.render(request, template, data)
Example #57
0
 def test_helpful_vote_no_id(self):
     """Throw helpful_vote a POST without an ID and see if it 400s."""
     response = self.client.post(reverse('wiki.document_vote', args=['hi']),
                                 {})
     eq_(400, response.status_code)
Example #58
0
def _get_next_url_fallback_localization(request):
    return get_next_url(request) or reverse('dashboards.localization')
Example #59
0
 def test_helpful_vote_bad_id(self):
     """Throw helpful_vote a bad ID, and see if it crashes."""
     response = self.client.post(reverse('wiki.document_vote', args=['hi']),
                                 {'revision_id': 'x'})
     eq_(404, response.status_code)
Example #60
0
 def test_home_redirect(self):
     """Going to /kb/ should redirect to /home/."""
     resp = self.client.get(reverse('wiki.home', locale='en-US'))
     self.assertRedirects(resp,
                          reverse('home', locale='en-US'),
                          status_code=301)