Example #1
0
    def test_lang_initial(self):
        """If no lang is set on the user, initial value is current locale."""
        # Lang is already set: don't change it.
        res = self.client.get(self.url)
        form = res.context['form']
        assert form.initial['lang'] == 'en-US'

        with self.activate('fr'):
            res = self.client.get(reverse('users.edit'))
            form = res.context['form']
            assert form.initial['lang'] == 'en-US'

        # Lang isn't set yet: initial value is set to the current locale.
        user = UserProfile.objects.get(email='*****@*****.**')
        user.lang = None
        user.save()

        res = self.client.get(self.url)
        form = res.context['form']
        assert form.initial['lang'] == 'en-US'

        with self.activate('fr'):
            res = self.client.get(reverse('users.edit'))
            form = res.context['form']
            assert form.initial['lang'] == 'fr'
Example #2
0
    def test_search_tools_within_a_category(self):
        # Pretend Foxy is the only bookmarks related search add-on
        AddonCategory.objects.all().delete()
        foxy = Addon.objects.get(name__localized_string='FoxyProxy Standard')
        foxy.type = amo.ADDON_SEARCH
        foxy.save()
        bookmarks = Category.objects.get(slug='bookmarks')
        AddonCategory.objects.create(
            addon=foxy, category=bookmarks, feature=False)

        url = reverse('browse.search-tools.rss',
                      args=('bookmarks',)) + '?sort=popular'
        response = self.client.get(url)
        assert response.status_code == 200
        doc = pq(response.content)

        assert doc('rss channel title')[0].text == (
            'Bookmarks :: Search Tools :: Add-ons for Firefox')

        link = doc('rss channel link')[0].text
        rel_link = reverse('browse.search-tools.rss',
                           args=('bookmarks',)) + '?sort=popular'
        assert link.endswith(rel_link), ('Unexpected link: %r' % link)

        assert doc('rss channel description')[0].text == (
            "Search tools relating to Bookmarks")

        assert [e.text for e in doc('rss channel item title')] == (
            ['FoxyProxy Standard 2.17'])
Example #3
0
    def test_ban(self):
        ban_url = reverse('admin:users_userprofile_ban', args=(self.user.pk, ))
        wrong_ban_url = reverse(
            'admin:users_userprofile_ban', args=(self.user.pk + 42, ))
        user = user_factory()
        self.grant_permission(user, 'Admin:Tools')
        self.client.login(email=user.email)
        core.set_user(user)
        response = self.client.post(ban_url, follow=True)
        assert response.status_code == 403
        self.grant_permission(user, 'Users:Edit')
        response = self.client.get(ban_url, follow=True)
        assert response.status_code == 405  # Wrong http method.
        response = self.client.post(wrong_ban_url, follow=True)
        assert response.status_code == 404  # Wrong pk.

        self.user.reload()
        assert not self.user.deleted

        response = self.client.post(ban_url, follow=True)
        assert response.status_code == 200
        assert response.redirect_chain[-1][0].endswith(self.detail_url)
        assert response.redirect_chain[-1][1] == 302
        self.user.reload()
        assert self.user.deleted
        assert self.user.email
        alog = ActivityLog.objects.latest('pk')
        assert alog.action == amo.LOG.ADMIN_USER_BANNED.id
        assert alog.arguments == [self.user]
Example #4
0
    def test_version_update_info(self):
        addon = Addon.objects.get(pk=3615)
        response = self.client.get(
            reverse('addons.versions.update_info',
                    args=(addon.slug, self.version.version)))
        assert response.status_code == 200
        assert response['Content-Type'] == 'application/xhtml+xml'
        # pyquery is annoying to use with XML and namespaces. Use the HTML
        # parser, but do check that xmlns attribute is present (required by
        # Firefox for the notes to be shown properly).
        doc = PyQuery(response.content, parser='html')
        assert doc('html').attr('xmlns') == 'http://www.w3.org/1999/xhtml'
        assert doc('p').html() == 'Fix for an important bug'

        # Test update info in another language.
        with self.activate(locale='fr'):
            response = self.client.get(
                reverse('addons.versions.update_info',
                        args=(addon.slug, self.version.version)))
            assert response.status_code == 200
            assert response['Content-Type'] == 'application/xhtml+xml'
            assert '<br/>' in response.content, (
                'Should be using XHTML self-closing tags!')
            doc = PyQuery(response.content, parser='html')
            assert doc('html').attr('xmlns') == 'http://www.w3.org/1999/xhtml'
            assert doc('p').html() == (
                u"Quelque chose en français.<br/><br/>Quelque chose d'autre.")
Example #5
0
def sidebar(app):
    """Populates the sidebar with (categories, types)."""
    from olympia.addons.models import Category
    if app is None:
        return [], []

    # We muck with query to make order_by and extra_order_by play nice.
    q = Category.objects.filter(application=app.id, weight__gte=0,
                                type=amo.ADDON_EXTENSION)
    categories = order_by_translation(q, 'name')
    categories.query.extra_order_by.insert(0, 'weight')

    Type = collections.namedtuple('Type', 'id name url')
    base = urlresolvers.reverse('home')
    types = [Type(99, _('Collections'), base + 'collections/')]

    shown_types = {
        amo.ADDON_PERSONA: urlresolvers.reverse('browse.personas'),
        amo.ADDON_DICT: urlresolvers.reverse('browse.language-tools'),
        amo.ADDON_SEARCH: urlresolvers.reverse('browse.search-tools'),
        amo.ADDON_THEME: urlresolvers.reverse('browse.themes'),
    }
    titles = dict(amo.ADDON_TYPES,
                  **{amo.ADDON_DICT: _('Dictionaries & Language Packs')})
    for type_, url in shown_types.items():
        if type_ in app.types:
            types.append(Type(type_, titles[type_], url))

    return categories, sorted(types, key=lambda x: x.name)
Example #6
0
    def test_delete_picture(self, delete_picture_mock):
        delete_picture_url = reverse(
            'admin:users_userprofile_delete_picture', args=(self.user.pk, ))
        wrong_delete_picture_url = reverse(
            'admin:users_userprofile_delete_picture',
            args=(self.user.pk + 42, ))
        user = user_factory()
        self.grant_permission(user, 'Admin:Tools')
        self.client.login(email=user.email)
        core.set_user(user)
        response = self.client.post(delete_picture_url, follow=True)
        assert response.status_code == 403
        self.grant_permission(user, 'Users:Edit')
        response = self.client.get(delete_picture_url, follow=True)
        assert response.status_code == 405  # Wrong http method.
        response = self.client.post(wrong_delete_picture_url, follow=True)
        assert response.status_code == 404  # Wrong pk.

        assert delete_picture_mock.call_count == 0

        response = self.client.post(delete_picture_url, follow=True)
        assert response.status_code == 200
        assert response.redirect_chain[-1][0].endswith(self.detail_url)
        assert response.redirect_chain[-1][1] == 302

        assert delete_picture_mock.call_count == 1

        alog = ActivityLog.objects.latest('pk')
        assert alog.action == amo.LOG.ADMIN_USER_PICTURE_DELETED.id
        assert alog.arguments == [self.user]
Example #7
0
 def setUp(self):
     super(TestDetails, self).setUp()
     self.addon = self.get_addon()
     self.detail_url = reverse('discovery.addons.detail',
                               args=[self.addon.slug])
     self.eula_url = reverse('discovery.addons.eula',
                             args=[self.addon.slug])
def get_absolute_url(url):
    if isinstance(url, tuple):
        url = reverse(url[0], args=url[1:])
    else:
        url = reverse(url)

    return 'http://%s%s' % ('api', url)
Example #9
0
    def test_acl_collections_edit(self):
        # Test users in group with 'Collections:Edit' are allowed.
        user = UserProfile.objects.get(email='*****@*****.**')
        group = Group.objects.create(name='Staff', rules='Collections:Edit')
        GroupUser.objects.create(user=user, group=group)
        r = self.client.post(self.add_url, self.data, follow=True)
        self.login_regular()
        url_args = ['admin', self.slug]

        url = reverse('collections.edit', args=url_args)
        r = self.client.get(url)
        eq_(r.status_code, 200)

        url = reverse('collections.edit_addons', args=url_args)
        r = self.client.get(url)
        eq_(r.status_code, 405)
        # Passed acl check, but this view needs a POST.

        url = reverse('collections.edit_contributors', args=url_args)
        r = self.client.get(url)
        eq_(r.status_code, 405)
        # Passed acl check, but this view needs a POST.

        url = reverse('collections.edit_privacy', args=url_args)
        r = self.client.get(url)
        eq_(r.status_code, 405)
        # Passed acl check, but this view needs a POST.

        url = reverse('collections.delete', args=url_args)
        r = self.client.get(url)
        eq_(r.status_code, 200)
Example #10
0
def setup_viewer(request, file_obj):
    addon = file_obj.version.addon
    data = {
        'file': file_obj,
        'version': file_obj.version,
        'addon': addon,
        'status': False,
        'selected': {},
        'validate_url': ''
    }
    is_user_a_reviewer = acl.is_reviewer(request, addon)

    if (is_user_a_reviewer or acl.check_addon_ownership(
            request, addon, dev=True, ignore_disabled=True)):

        data['validate_url'] = reverse('devhub.json_file_validation',
                                       args=[addon.slug, file_obj.id])
        data['automated_signing'] = file_obj.automated_signing

        if file_obj.has_been_validated:
            data['validation_data'] = file_obj.validation.processed_validation

    if is_user_a_reviewer:
        data['file_link'] = {
            'text': ugettext('Back to review'),
            'url': reverse('reviewers.review', args=[addon.slug])
        }
    else:
        data['file_link'] = {
            'text': ugettext('Back to add-on'),
            'url': reverse('addons.detail', args=[addon.pk])
        }
    return data
Example #11
0
 def get_context_data(self):
     addon_url = self.addon.get_url_path(add_prefix=False)
     # We need to display the name in some language that is relevant to the
     # recipient(s) instead of using the reviewer's. addon.default_locale
     # should work.
     if self.addon.name.locale != self.addon.default_locale:
         lang = to_language(self.addon.default_locale)
         with translation.override(lang):
             addon = Addon.unfiltered.get(pk=self.addon.pk)
     else:
         addon = self.addon
     review_url_kw = {'addon_id': self.addon.pk}
     if (self.version and
             self.version.channel == amo.RELEASE_CHANNEL_UNLISTED):
         review_url_kw['channel'] = 'unlisted'
         dev_ver_url = reverse(
             'devhub.addons.versions',
             args=[self.addon.id])
     else:
         dev_ver_url = self.addon.get_dev_url('versions')
     return {'name': addon.name,
             'number': self.version.version if self.version else '',
             'reviewer': self.user.display_name,
             'addon_url': absolutify(addon_url),
             'dev_versions_url': absolutify(dev_ver_url),
             'review_url': absolutify(reverse('reviewers.review',
                                              kwargs=review_url_kw,
                                              add_prefix=False)),
             'comments': self.data.get('comments'),
             'SITE_URL': settings.SITE_URL}
Example #12
0
def legacy_theme_redirects(request, category=None, category_name=None):
    url = None

    if category_name is not None:
        # This format is for the Complete Themes RSS feed.
        url = reverse('browse.themes.rss', args=[category_name])
    else:
        if not category or category == 'all':
            url = reverse('browse.personas')
        else:
            try:
                # Theme?
                cat = Category.objects.filter(slug=category,
                                              type=amo.ADDON_PERSONA)[0]
            except IndexError:
                pass
            else:
                # Hey, it was a Theme.
                url = reverse('browse.personas', args=[cat.slug])

    if url:
        if 'sort' in request.GET:
            url = amo.utils.urlparams(url, sort=request.GET['sort'])
        return redirect(url, permanent=not settings.DEBUG)
    else:
        raise Http404
Example #13
0
def sidebar(app):
    """Populates the sidebar with (categories, types)."""
    from olympia.addons.models import Category
    if app is None:
        return [], []

    # Fetch categories...
    qs = Category.objects.filter(application=app.id, weight__gte=0,
                                 type=amo.ADDON_EXTENSION)
    # Now sort them in python according to their name property (which looks up
    # the translated name using gettext + our constants)
    categories = sorted(qs, key=attrgetter('weight', 'name'))

    Type = collections.namedtuple('Type', 'id name url')
    base = urlresolvers.reverse('home')
    types = [Type(99, ugettext('Collections'), base + 'collections/')]

    shown_types = {
        amo.ADDON_PERSONA: urlresolvers.reverse('browse.personas'),
        amo.ADDON_DICT: urlresolvers.reverse('browse.language-tools'),
        amo.ADDON_SEARCH: urlresolvers.reverse('browse.search-tools'),
        amo.ADDON_THEME: urlresolvers.reverse('browse.themes'),
    }
    titles = dict(
        amo.ADDON_TYPES,
        **{amo.ADDON_DICT: ugettext('Dictionaries & Language Packs')})
    for type_, url in shown_types.items():
        if type_ in app.types:
            types.append(Type(type_, titles[type_], url))

    return categories, sorted(types, key=lambda x: x.name)
    def login(self, account):
        log.debug('creating fxa account')
        fxa_account, email_account = helpers.get_fxa_account()

        log.debug('calling login/start to generate fxa_state')
        response = self.client.get(
            reverse('accounts.login_start'),
            allow_redirects=False)

        params = dict(urlparse.parse_qsl(response.headers['Location']))
        fxa_state = params['state']

        log.debug('Get browser id session token')
        fxa_session = helpers.get_fxa_client().login(
            email=fxa_account.email,
            password=fxa_account.password)

        oauth_client = fxa_oauth.Client(
            client_id=FXA_CONFIG['client_id'],
            client_secret=FXA_CONFIG['client_secret'],
            server_url=FXA_CONFIG['oauth_host'])

        log.debug('convert browser id session token into oauth code')
        oauth_code = oauth_client.authorize_code(fxa_session, scope='profile')

        # Now authenticate the user, this will verify the user on the
        response = self.client.get(
            reverse('accounts.authenticate'),
            params={
                'state': fxa_state,
                'code': oauth_code,
            }
        )
Example #15
0
    def test_delete_link(self):
        # Create an addon by user 1.
        self.create_collection()

        url = reverse('collections.edit_contributors',
                      args=['admin', self.slug])
        self.client.post(
            url,
            {
                'contributor': '*****@*****.**',
                'application': 1,
                'type': 1
            },
            follow=True)
        url = reverse('collections.edit', args=['admin', self.slug])

        r = self.client.get(url)
        assert r.status_code == 200
        doc = pq(r.content)
        assert len(doc('a.delete')) == 2

        self.login_regular()
        r = self.client.get(url)
        assert r.status_code == 200
        doc = pq(r.content)
        assert len(doc('a.delete')) == 0
Example #16
0
 def test_nonapp_pages(self):
     self._check({
         '/en-US/pages/developer_faq': reverse('pages.dev_faq'),
         '/en-US/pages/review_guide': reverse('pages.review_guide'),
         '/en-US/pages/developer_agreement': reverse(
             'devhub.docs', args=['policies/agreement']),
     })
Example #17
0
    def test_forbidden_edit(self):
        self.create_collection()
        self.login_regular()
        url_args = ['admin', self.slug]

        url = reverse('collections.edit', args=url_args)
        r = self.client.get(url)
        assert r.status_code == 403
        r = self.client.post(url)
        assert r.status_code == 403

        url = reverse('collections.edit_addons', args=url_args)
        r = self.client.get(url)
        assert r.status_code == 403
        r = self.client.post(url)
        assert r.status_code == 403

        url = reverse('collections.edit_contributors', args=url_args)
        r = self.client.get(url)
        assert r.status_code == 403
        r = self.client.post(url)
        assert r.status_code == 403

        url = reverse('collections.edit_privacy', args=url_args)
        r = self.client.get(url)
        assert r.status_code == 403
        r = self.client.post(url)
        assert r.status_code == 403

        url = reverse('collections.delete', args=url_args)
        r = self.client.get(url)
        assert r.status_code == 403
        r = self.client.post(url)
        assert r.status_code == 403
Example #18
0
    def test_user_review_history(self):
        self.theme_factory()

        reviewer = self.create_and_become_reviewer()

        res = self.client.get(reverse('editors.themes.history'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 0

        theme = Persona.objects.all()[0]
        for x in range(3):
            ActivityLog.create(
                amo.LOG.THEME_REVIEW, theme.addon, user=reviewer,
                details={'action': rvw.ACTION_APPROVE,
                         'comment': '', 'reject_reason': ''})

        res = self.client.get(reverse('editors.themes.history'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 3

        res = self.client.get(reverse('editors.themes.logs'))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('tbody tr').length == 3 * 2  # Double for comment rows.
Example #19
0
    def test_featured_extensions_with_category_es_ES(self):
        addon = self.addon
        res = self.client.get(reverse('browse.extensions', args=['bookmarks']))
        assert addon in res.context['filter'].all()['featured']

        self.change_addoncategory(addon, 'es')
        res = self.client.get(reverse('browse.extensions', args=['bookmarks']))
        assert addon not in res.context['filter'].all()['featured']
Example #20
0
 def test_upload_link_label_in_edit_nav(self):
     url = reverse('devhub.versions.edit',
                   args=(self.addon.slug, self.version.pk))
     r = self.client.get(url)
     link = pq(r.content)('.addon-status>.addon-upload>strong>a')
     assert link.text() == 'Upload New Version'
     assert link.attr('href') == '%s#version-upload' % (
         reverse('devhub.addons.versions', args=[self.addon.slug]))
Example #21
0
 def setUp(self):
     super(TestVotes, self).setUp()
     self.client.login(username='******', password='******')
     args = ['fligtar', 'slug']
     Collection.objects.create(slug='slug', author_id=9945)
     self.c_url = reverse('collections.detail', args=args)
     self.up = reverse('collections.vote', args=args + ['up'])
     self.down = reverse('collections.vote', args=args + ['down'])
Example #22
0
    def test_request_with_unkown_email(self):
        r = self.client.post(
            reverse('password_reset_form'),
            {'email': '*****@*****.**'}
        )

        eq_(len(mail.outbox), 0)
        self.assert3xx(r, reverse('password_reset_done'))
 def test_dashboard(self):
     """Make sure the dashboard is getting data."""
     self.log_creates(10)
     r = self.client.get(reverse('devhub.addons'))
     doc = pq(r.content)
     assert len(doc('li.item')) == 4
     assert doc('.subscribe-feed').attr('href')[:-32] == (
         reverse('devhub.feed_all') + '?privaterss=')
Example #24
0
 def test_nonapp_pages(self):
     self._check({
         '/en-US/pages/review_guide': reverse('pages.review_guide'),
     })
     r = self.client.get('/en-US/firefox/pages/developer_agreement',
                         follow=False)
     self.assert3xx(r, reverse(
         'devhub.docs', args=['policies/agreement']), 301)
Example #25
0
 def test_login_protected(self):
     self.client.logout()
     r = self.client.get(reverse('devhub.bulk_compat_result',
                                 args=[self.addon.slug, self.result.id]))
     assert r.status_code == 302
     r = self.client.post(reverse('devhub.json_bulk_compat_result',
                                  args=[self.addon.slug, self.result.id]))
     assert r.status_code == 302
Example #26
0
    def test_reverse(self):
        # Make sure it works outside the request.
        urlresolvers.clean_url_prefixes()  # Modified in BaseTestCase.
        assert urlresolvers.reverse('home') == '/'

        # With a request, locale and app prefixes work.
        Client().get('/')
        assert urlresolvers.reverse('home') == '/en-US/firefox/'
    def test_reverse(self):
        # Make sure it works outside the request.
        urlresolvers.clean_url_prefixes()  # Modified in BaseTestCase.
        eq_(urlresolvers.reverse("home"), "/")

        # With a request, locale and app prefixes work.
        Client().get("/")
        eq_(urlresolvers.reverse("home"), "/en-US/firefox/")
Example #28
0
 def test_breadcrumbs(self):
     r = self.client.get(self.add_url)
     expected = [
         ('Add-ons for Firefox', reverse('home')),
         ('Collections', reverse('collections.list')),
         ('Create', None)
     ]
     amo.tests.check_links(expected, pq(r.content)('#breadcrumbs li'))
    def get_response(self, **kwargs):
        url = reverse('devhub.feed_all')
        if 'addon' in kwargs:
            url = reverse('devhub.feed', args=(kwargs['addon'],))

        if kwargs:
            url += '?' + urlencode(kwargs)

        return self.client.get(url, follow=True)
Example #30
0
 def test_filename_not_uuidfied(self, validate_mock):
     validate_mock.return_value = json.dumps(amo.VALIDATOR_SKELETON_RESULTS)
     url = reverse('devhub.upload')
     data = open(get_image_path('animated.png'), 'rb')
     self.client.post(url, {'upload': data})
     upload = FileUpload.objects.get()
     response = self.client.get(
         reverse('devhub.upload_detail', args=(upload.uuid.hex,)))
     assert 'Validation Results for animated.png' in response.content
Example #31
0
def redirect(request, viewer, key):
    new = Token(data=[viewer.file.id, key])
    new.save()
    url = reverse('files.serve', args=[viewer, key])
    url = urlparams(url, token=new.token)
    return http.HttpResponseRedirect(url)
Example #32
0
 def links(self):
     return [Link(_(u'Add to {0}').format(unicode(self.app.pretty)),
                  reverse('addons.detail', args=[amo.PERSONAS_ADDON_ID]))]
Example #33
0
 def get_context(self, name, value, attrs):
     context = super(SourceFileInput, self).get_context(name, value, attrs)
     if value and hasattr(value, 'instance'):
         context['download_url'] = reverse('downloads.source',
                                           args=(value.instance.pk, ))
     return context
Example #34
0
def home(request):
    if (not acl.action_allowed(request, 'Addons', 'Review') and
            acl.action_allowed(request, 'Personas', 'Review')):
        return http.HttpResponseRedirect(reverse('editors.themes.home'))

    motd_editable = acl.action_allowed(request, 'AddonReviewerMOTD', 'Edit')
    durations = (('new', _('New Add-ons (Under 5 days)')),
                 ('med', _('Passable (5 to 10 days)')),
                 ('old', _('Overdue (Over 10 days)')))

    limited_reviewer = is_limited_reviewer(request)
    progress, percentage = _editor_progress(limited_reviewer=limited_reviewer)
    unlisted_progress, unlisted_percentage = _editor_progress(
        unlisted=True, limited_reviewer=limited_reviewer)
    reviews_max_display = getattr(settings, 'EDITOR_REVIEWS_MAX_DISPLAY', 5)
    reviews_total = ActivityLog.objects.total_reviews()[:reviews_max_display]
    reviews_monthly = (
        ActivityLog.objects.monthly_reviews()[:reviews_max_display])
    reviews_total_count = ActivityLog.objects.user_approve_reviews(
        request.user).count()
    reviews_monthly_count = (
        ActivityLog.objects.current_month_user_approve_reviews(
            request.user).count())

    # Try to read user position from retrieved reviews.
    # If not available, query for it.
    reviews_total_position = (
        ActivityLog.objects.user_position(reviews_total, request.user)
        or ActivityLog.objects.total_reviews_user_position(request.user))

    reviews_monthly_position = (
        ActivityLog.objects.user_position(reviews_monthly, request.user)
        or ActivityLog.objects.monthly_reviews_user_position(request.user))

    limited_reviewer = is_limited_reviewer(request)
    data = context(
        request,
        reviews_total=reviews_total,
        reviews_monthly=reviews_monthly,
        reviews_total_count=reviews_total_count,
        reviews_monthly_count=reviews_monthly_count,
        reviews_total_position=reviews_total_position,
        reviews_monthly_position=reviews_monthly_position,
        new_editors=EventLog.new_editors(),
        eventlog=ActivityLog.objects.editor_events()[:6],
        progress=progress,
        unlisted_progress=unlisted_progress,
        percentage=percentage,
        unlisted_percentage=unlisted_percentage,
        durations=durations,
        reviews_max_display=reviews_max_display,
        motd_editable=motd_editable,
        queue_counts_total=queue_counts(admin_reviewer=True,
                                        limited_reviewer=limited_reviewer),
        unlisted_queue_counts_total=queue_counts(
            admin_reviewer=True,
            unlisted=True,
            limited_reviewer=limited_reviewer),
    )

    return render(request, 'editors/home.html', data)
def themes_queue_rereview(request):
    # By default, redirect back to the queue after a commit.
    request.session['theme_redirect_url'] = reverse(
        'editors.themes.queue_rereview')

    return _themes_queue(request, rereview=True)
Example #36
0
 def test_perm(self):
     # Personas:Review allow access to deleted themes as well.
     self.login('*****@*****.**')
     response = self.client.get(reverse('reviewers.themes.deleted'))
     assert response.status_code == 200
def themes_single(request, slug):
    """
    Like a detail page, manually review a single theme if it is pending
    and isn't locked.
    """
    reviewer = request.user
    reviewable = True

    # Don't review an already reviewed theme.
    theme = get_object_or_404(Persona, addon__slug=slug)
    if (theme.addon.status != amo.STATUS_PENDING
            and not theme.rereviewqueuetheme_set.all()):
        reviewable = False

    if (not settings.ALLOW_SELF_REVIEWS
            and not acl.action_allowed(request, 'Admin', '%')
            and theme.addon.has_author(request.user)):
        reviewable = False
    else:
        # Don't review a locked theme (that's not locked to self).
        try:
            lock = theme.themelock
            if (lock.reviewer.id != reviewer.id
                    and lock.expiry > datetime.datetime.now()):
                reviewable = False
            elif (lock.reviewer.id != reviewer.id
                  and lock.expiry < datetime.datetime.now()):
                # Steal expired lock.
                lock.reviewer = reviewer
                lock.expiry = get_updated_expiry()
                lock.save()
            else:
                # Update expiry.
                lock.expiry = get_updated_expiry()
                lock.save()
        except ThemeLock.DoesNotExist:
            # Create lock if not created.
            ThemeLock.objects.create(theme=theme,
                                     reviewer=reviewer,
                                     expiry=get_updated_expiry())

    ThemeReviewFormset = formset_factory(forms.ThemeReviewForm)
    formset = ThemeReviewFormset(initial=[{'theme': theme.id}])

    # Since we started the review on the single page, we want to return to the
    # single page rather than get shot back to the queue.
    request.session['theme_redirect_url'] = reverse('editors.themes.single',
                                                    args=[theme.addon.slug])

    rereview = (theme.rereviewqueuetheme_set.all()[0]
                if theme.rereviewqueuetheme_set.exists() else None)
    return render(
        request, 'editors/themes/single.html',
        context(
            **{
                'formset':
                formset,
                'theme':
                rereview if rereview else theme,
                'theme_formsets':
                zip([rereview if rereview else theme], formset),
                'theme_reviews':
                paginate(
                    request,
                    ActivityLog.objects.filter(
                        action=amo.LOG.THEME_REVIEW.id,
                        _arguments__contains=theme.addon.id)),
                'actions':
                get_actions_json(),
                'theme_count':
                1,
                'rereview':
                rereview,
                'reviewable':
                reviewable,
                'reject_reasons':
                rvw.THEME_REJECT_REASONS,
                'action_dict':
                rvw.REVIEW_ACTIONS,
                'tab':
                ('flagged' if theme.addon.status == amo.STATUS_REVIEW_PENDING
                 else 'rereview' if rereview else 'pending')
            }))
Example #38
0
    def test_commit(self, copy_mock, create_preview_mock, send_mail_jinja_mock,
                    version_changed_mock, theme_checksum_mock, message_mock):
        if self.flagged:
            # Feels redundant to test this for flagged queue.
            return

        themes = []
        for x in range(5):
            themes.append(self.theme_factory().persona)
        form_data = amo.tests.formset(initial_count=5, total_count=6)

        # Create locks.
        reviewer = self.create_and_become_reviewer()
        for index, theme in enumerate(themes):
            ThemeLock.objects.create(
                theme=theme,
                reviewer=reviewer,
                expiry=datetime.datetime.now() +
                datetime.timedelta(minutes=amo.THEME_LOCK_EXPIRY))
            form_data['form-%s-theme' % index] = str(theme.id)

        # Build formset.
        actions = (
            (str(amo.ACTION_MOREINFO), 'moreinfo', ''),
            (str(amo.ACTION_FLAG), 'flag', ''),
            (str(amo.ACTION_DUPLICATE), 'duplicate', ''),
            (str(amo.ACTION_REJECT), 'reject', '1'),
            (str(amo.ACTION_APPROVE), '', ''),
        )
        for index, action in enumerate(actions):
            action, comment, reject_reason = action
            form_data['form-%s-action' % index] = action
            form_data['form-%s-comment' % index] = comment
            form_data['form-%s-reject_reason' % index] = reject_reason

        old_version = themes[4].addon.current_version.version

        # Test edge case where pending theme also has re-review.
        for theme in (themes[3], themes[4]):
            RereviewQueueTheme.objects.create(theme=theme,
                                              header='',
                                              footer='')

        # Commit.
        # Activate another locale than en-US, and make sure emails to theme
        # authors are NOT translated, but the message to the review IS.
        with self.activate(locale='fr'):
            response = self.client.post(reverse('reviewers.themes.commit'),
                                        form_data)
            self.assert3xx(response, reverse('reviewers.themes.queue_themes'))

        if self.rereview:
            # Original design of reuploaded themes should stay public.
            for i in range(4):
                assert themes[i].addon.status == amo.STATUS_PUBLIC
                assert themes[i].header == 'header'
                assert themes[i].footer == 'footer'

            assert copy_mock.call_count == 2
            assert copy_mock.call_args_list[0][0][0].endswith('pending_header')
            assert copy_mock.call_args_list[0][0][1].endswith('header')
            assert copy_mock.call_args_list[1][0][0].endswith('pending_footer')
            assert copy_mock.call_args_list[1][0][1].endswith('footer')

            assert create_preview_mock.call_count == 1
            create_preview_args = create_preview_mock.call_args_list[0][1]
            assert create_preview_args['src'].endswith('header')
            assert create_preview_args['full_dst'][0].endswith('preview.png')
            assert create_preview_args['full_dst'][1].endswith('icon.png')

            # Approved/rejected/dupe themes have their images deleted
            # leaving only 2 RQT objects. Can't flag a rereview theme yet, and
            # moreinfo does nothing but email the artist.
            assert RereviewQueueTheme.objects.count() == 2

            # Test version incremented.
            assert themes[4].addon.reload().current_version.version == (
                str(float(old_version) + 1))

            # Checksum was recalculated for that theme.
            assert theme_checksum_mock.call_count == 1
            assert theme_checksum_mock.call_args_list[0][0][0] == themes[4]
        else:
            assert themes[0].addon.reload().status == amo.STATUS_REVIEW_PENDING
            assert themes[1].addon.reload().status == amo.STATUS_REVIEW_PENDING
            assert themes[2].addon.reload().status == amo.STATUS_REJECTED
            assert themes[3].addon.reload().status == amo.STATUS_REJECTED

            assert theme_checksum_mock.call_count == 0
        assert themes[4].addon.reload().status == amo.STATUS_PUBLIC
        assert ActivityLog.objects.count() == 4 if self.rereview else 5

        expected_calls = [
            mock.call('A question about your Theme submission',
                      'reviewers/themes/emails/moreinfo.html', {
                          'reason': None,
                          'comment': u'moreinfo',
                          'theme': themes[0],
                          'reviewer_email': u'*****@*****.**',
                          'base_url': 'http://testserver'
                      },
                      headers={'Reply-To': settings.THEMES_EMAIL},
                      from_email=settings.ADDONS_EMAIL,
                      recipient_list=set([])),
            mock.call('Theme submission flagged for review',
                      'reviewers/themes/emails/flag_reviewer.html', {
                          'reason': None,
                          'comment': u'flag',
                          'theme': themes[1],
                          'base_url': 'http://testserver'
                      },
                      headers={'Reply-To': settings.THEMES_EMAIL},
                      from_email=settings.ADDONS_EMAIL,
                      recipient_list=[settings.THEMES_EMAIL]),
            mock.call('A problem with your Theme submission',
                      'reviewers/themes/emails/reject.html', {
                          'reason': u'Duplicate Submission',
                          'comment': u'duplicate',
                          'theme': themes[2],
                          'base_url': 'http://testserver'
                      },
                      headers={'Reply-To': settings.THEMES_EMAIL},
                      from_email=settings.ADDONS_EMAIL,
                      recipient_list=set([])),
            mock.call('A problem with your Theme submission',
                      'reviewers/themes/emails/reject.html', {
                          'reason': u'Sexual or pornographic content',
                          'comment': u'reject',
                          'theme': themes[3],
                          'base_url': 'http://testserver'
                      },
                      headers={'Reply-To': settings.THEMES_EMAIL},
                      from_email=settings.ADDONS_EMAIL,
                      recipient_list=set([])),
            mock.call('Thanks for submitting your Theme',
                      'reviewers/themes/emails/approve.html', {
                          'reason': None,
                          'comment': u'',
                          'theme': themes[4],
                          'base_url': 'http://testserver'
                      },
                      headers={'Reply-To': settings.THEMES_EMAIL},
                      from_email=settings.ADDONS_EMAIL,
                      recipient_list=set([]))
        ]
        if self.rereview:
            assert send_mail_jinja_mock.call_count == 4
            assert send_mail_jinja_mock.call_args_list[0] == expected_calls[0]
            assert send_mail_jinja_mock.call_args_list[1] == expected_calls[2]
            assert send_mail_jinja_mock.call_args_list[2] == expected_calls[3]
            assert send_mail_jinja_mock.call_args_list[3] == expected_calls[4]
        else:
            assert send_mail_jinja_mock.call_count == 5
            assert send_mail_jinja_mock.call_args_list[0] == expected_calls[0]
            assert send_mail_jinja_mock.call_args_list[1] == expected_calls[1]
            assert send_mail_jinja_mock.call_args_list[2] == expected_calls[2]
            assert send_mail_jinja_mock.call_args_list[3] == expected_calls[3]
            assert send_mail_jinja_mock.call_args_list[4] == expected_calls[4]

            assert message_mock.call_args_list[0][0][1] == (
                u'5 validations de thèmes réalisées avec succès '
                u'(+15 points, 15 au total).')

        # Reviewer points accrual.
        assert ReviewerScore.objects.all()[0].score > 0
Example #39
0
def notify_compatibility_chunk(users, job, data, **kw):
    log.info('[%s@%s] Sending notification mail for job %s.'
             % (len(users), notify_compatibility.rate_limit, job.pk))
    core.set_user(get_task_user())
    dry_run = data['preview_only']
    app_id = job.target_version.application
    stats = collections.defaultdict(int)
    stats['processed'] = 0
    stats['is_dry_run'] = int(dry_run)

    for user in users:
        stats['processed'] += 1

        try:
            for addon in chain(user.passing_addons, user.failing_addons):
                try:
                    results = job.result_set.filter(file__version__addon=addon)

                    addon.links = [
                        absolutify(reverse('devhub.bulk_compat_result',
                                           args=[addon.slug, r.pk]))
                        for r in results]

                    version = (
                        addon.current_version or addon.find_latest_version(
                            channel=amo.RELEASE_CHANNEL_LISTED))
                    addon.compat_link = absolutify(reverse(
                        'devhub.versions.edit', args=[addon.pk, version.pk]))
                except:
                    task_error = sys.exc_info()
                    log.error(u'Bulk validation email error for user %s, '
                              u'addon %s: %s: %s'
                              % (user.email, addon.slug,
                                 task_error[0], task_error[1]), exc_info=False)

            context = Context({
                'APPLICATION': unicode(amo.APP_IDS[job.application].pretty),
                'VERSION': job.target_version.version,
                'PASSING_ADDONS': user.passing_addons,
                'FAILING_ADDONS': user.failing_addons,
            })

            log.info(u'Emailing %s%s for %d addons about '
                     'bulk validation job %s'
                     % (user.email,
                        ' [PREVIEW]' if dry_run else '',
                        len(user.passing_addons) + len(user.failing_addons),
                        job.pk))
            args = (Template(data['subject']).render(context),
                    Template(data['text']).render(context))
            kwargs = dict(from_email=settings.DEFAULT_FROM_EMAIL,
                          recipient_list=[user.email])
            if dry_run:
                job.preview_notify_mail(*args, **kwargs)
            else:
                stats['author_emailed'] += 1
                send_mail(*args, **kwargs)
                ActivityLog.create(
                    amo.LOG.BULK_VALIDATION_USER_EMAILED,
                    user,
                    details={'passing': [a.id for a in user.passing_addons],
                             'failing': [a.id for a in user.failing_addons],
                             'target': job.target_version.version,
                             'application': app_id})
        except:
            task_error = sys.exc_info()
            log.error(u'Bulk validation email error for user %s: %s: %s'
                      % (user.email,
                         task_error[0], task_error[1]), exc_info=False)

    log.info('[%s@%s] bulk email stats for job %s: {%s}'
             % (len(users), notify_compatibility.rate_limit, job.pk,
                ', '.join('%s: %s' % (k, stats[k])
                          for k in sorted(stats.keys()))))
Example #40
0
 def setUp(self):
     self.list_url = reverse('admin:files_file_changelist')
Example #41
0
def update_info_redirect(request, version_id):
    version = get_object_or_404(Version.objects, pk=version_id)
    return redirect(reverse('addons.versions.update_info',
                            args=(version.addon.id, version.version)),
                    permanent=True)
Example #42
0
 def setUp(self):
     super(TestThemeQueue, self).setUp()
     self.queue_url = reverse('reviewers.themes.queue_themes')
Example #43
0
 def check_permissions(self, slug, status_code):
     for url in [
             reverse('reviewers.themes.queue_themes'),
             reverse('reviewers.themes.single', args=[slug])
     ]:
         assert self.client.get(url).status_code == status_code
Example #44
0
 def test_super_review_email(self):
     self.setup_data(amo.STATUS_NULL)
     self.helper.handler.process_super_review()
     url = reverse('editors.review', args=[self.addon.pk], add_prefix=False)
     assert url in mail.outbox[1].body
Example #45
0
 def test_redirect_to_new_dashboard(self):
     response = self.client.get('/en-US/reviewers/themes')
     self.assert3xx(response,
                    reverse('reviewers.dashboard'),
                    status_code=301)
Example #46
0
 def test_queue_page(self):
     url = reverse('reviewers.themes.single', args=[self.theme.slug])
     self.assertNameAndNoXSS(url)
Example #47
0
    def test_update_legacy_theme(self, amo_copy_stored_file_mock,
                                 create_persona_preview_mock,
                                 copy_stored_filed_mock, theme_checksum_mock,
                                 send_mail_jinja_mock):
        """
        Test updating themes that were submitted from GetPersonas.
        STR the bug this test fixes:

        - Reupload a legacy theme and approve it.
        - On approving, it would make a preview image with the destination as
         'preview.png' and 'icon.png', but legacy themes use
         'preview.jpg' and 'preview_small.jpg'.
        - Thus the preview images were not being updated, but the header/footer
          images were.
        """
        theme = self.theme_factory(status=amo.STATUS_PUBLIC).persona
        theme.header = 'Legacy-header3H.png'
        theme.footer = 'Legacy-footer3H-Copy.jpg'
        theme.persona_id = 5
        theme.save()
        form_data = amo.tests.formset(initial_count=5, total_count=6)

        RereviewQueueTheme.objects.create(theme=theme,
                                          header='pending_header.png',
                                          footer='pending_footer.png')

        # Create lock.
        reviewer = self.create_and_become_reviewer()
        ThemeLock.objects.create(theme=theme,
                                 reviewer=reviewer,
                                 expiry=self.days_ago(-1))
        form_data['form-0-theme'] = str(theme.id)

        # Build formset.
        form_data['form-0-action'] = str(amo.ACTION_APPROVE)

        # Commit.
        self.client.post(reverse('reviewers.themes.commit'), form_data)

        # Check nothing has changed.
        assert theme.header == 'Legacy-header3H.png'
        assert theme.footer == 'Legacy-footer3H-Copy.jpg'
        theme.thumb_path.endswith('preview.jpg')
        theme.icon_path.endswith('preview_small.jpg')
        theme.preview_path.endswith('preview_large.jpg')

        # Test calling create_persona_preview_images.
        assert (create_persona_preview_mock.call_args_list[0][1]['full_dst']
                [0].endswith('preview.jpg'))
        assert (create_persona_preview_mock.call_args_list[0][1]['full_dst']
                [1].endswith('preview_small.jpg'))

        # pending_header should be mv'ed to Legacy-header3H.png.
        assert (amo_copy_stored_file_mock.call_args_list[0][0][0].endswith(
            'pending_header'))
        assert (amo_copy_stored_file_mock.call_args_list[0][0][1].endswith(
            'Legacy-header3H.png'))
        # pending_footer should be mv'ed to Legacy-footer-Copy3H.png.
        assert (amo_copy_stored_file_mock.call_args_list[1][0][0].endswith(
            'pending_footer'))
        assert (amo_copy_stored_file_mock.call_args_list[1][0][1].endswith(
            'Legacy-footer3H-Copy.jpg'))

        assert (copy_stored_filed_mock.call_args_list[0][0][0].endswith(
            'preview.jpg'))
        assert (copy_stored_filed_mock.call_args_list[0][0][1].endswith(
            'preview_large.jpg'))

        # We re-calculated the theme checksum from the newest data.
        assert theme_checksum_mock.call_count == 1
        assert theme_checksum_mock.call_args_list[0][0][0] == theme
Example #48
0
def queue(request):
    return redirect(reverse('editors.queue_pending'))
Example #49
0
 def test_table(self):
     self.login('*****@*****.**')
     response = self.client.get(reverse('reviewers.themes.deleted'))
     assert response.status_code == 200
     assert (self.deleted.name.localized_string
             in smart_text(response.content))
Example #50
0
 def setUp(self):
     super(TestThemeQueueFlagged, self).setUp()
     self.status = amo.STATUS_REVIEW_PENDING
     self.flagged = True
     self.queue_url = reverse('reviewers.themes.queue_flagged')
Example #51
0
def review(request, addon):
    if not addon.is_listed and not acl.check_unlisted_addons_reviewer(request):
        raise http.Http404

    version = addon.latest_version

    if not settings.ALLOW_SELF_REVIEWS and addon.has_author(request.user):
        amo.messages.warning(request, _('Self-reviews are not allowed.'))
        return redirect(reverse('editors.queue'))

    form_helper = ReviewHelper(request=request, addon=addon, version=version)
    form = forms.ReviewForm(request.POST or None, helper=form_helper)
    queue_type = ('prelim' if form.helper.review_type == 'preliminary'
                  else form.helper.review_type)
    if addon.is_listed:
        redirect_url = reverse('editors.queue_%s' % queue_type)
    else:
        redirect_url = reverse('editors.unlisted_queue_%s' % queue_type)

    is_admin = acl.action_allowed(request, 'Addons', 'Edit')

    if request.method == 'POST' and form.is_valid():
        form.helper.process()
        if form.cleaned_data.get('notify'):
            EditorSubscription.objects.get_or_create(user=request.user,
                                                     addon=addon)
        if form.cleaned_data.get('adminflag') and is_admin:
            addon.update(admin_review=False)
        amo.messages.success(request, _('Review successfully processed.'))
        return redirect(redirect_url)

    # Kick off validation tasks for any files in this version which don't have
    # cached validation, since editors will almost certainly need to access
    # them. But only if we're not running in eager mode, since that could mean
    # blocking page load for several minutes.
    if version and not getattr(settings, 'CELERY_ALWAYS_EAGER', False):
        for file_ in version.files.all():
            if not file_.has_been_validated:
                devhub_tasks.validate(file_)

    canned = AddonCannedResponse.objects.all()
    actions = form.helper.actions.items()

    statuses = [amo.STATUS_PUBLIC, amo.STATUS_LITE,
                amo.STATUS_LITE_AND_NOMINATED]

    try:
        show_diff = version and (
            addon.versions.exclude(id=version.id).filter(
                files__isnull=False, created__lt=version.created,
                files__status__in=statuses).latest())
    except Version.DoesNotExist:
        show_diff = None

    # The actions we should show a minimal form from.
    actions_minimal = [k for (k, a) in actions if not a.get('minimal')]

    versions = (Version.unfiltered.filter(addon=addon)
                                  .exclude(files__status=amo.STATUS_BETA)
                                  .order_by('-created')
                                  .transform(Version.transformer_activity)
                                  .transform(Version.transformer))

    class PseudoVersion(object):
        def __init__(self):
            self.all_activity = []

        all_files = ()
        approvalnotes = None
        compatible_apps_ordered = ()
        releasenotes = None
        status = 'Deleted'
        deleted = True

        @property
        def created(self):
            return self.all_activity[0].created

        @property
        def version(self):
            return (self.all_activity[0].activity_log
                        .details.get('version', '[deleted]'))

    # Grab review history for deleted versions of this add-on
    # Version are soft-deleted now but we need this for older deletions.
    comments = (CommentLog.objects
                .filter(activity_log__action__in=amo.LOG_REVIEW_QUEUE,
                        activity_log__versionlog=None,
                        activity_log__addonlog__addon=addon)
                .order_by('created')
                .select_related('activity_log'))

    comment_versions = defaultdict(PseudoVersion)
    for c in comments:
        c.version = c.activity_log.details.get('version', c.created)
        comment_versions[c.version].all_activity.append(c)

    all_versions = comment_versions.values()
    all_versions.extend(versions)
    all_versions.sort(key=lambda v: v.created,
                      reverse=True)

    pager = amo.utils.paginate(request, all_versions, 10)

    num_pages = pager.paginator.num_pages
    count = pager.paginator.count

    try:
        flags = ViewQueue.objects.get(id=addon.id).flags
    except ViewQueue.DoesNotExist:
        flags = []

    user_changes_actions = [
        amo.LOG.ADD_USER_WITH_ROLE.id,
        amo.LOG.CHANGE_USER_WITH_ROLE.id,
        amo.LOG.REMOVE_USER_WITH_ROLE.id]
    user_changes_log = AddonLog.objects.filter(
        activity_log__action__in=user_changes_actions,
        addon=addon).order_by('id')
    ctx = context(request, version=version, addon=addon,
                  pager=pager, num_pages=num_pages, count=count, flags=flags,
                  form=form, canned=canned, is_admin=is_admin,
                  show_diff=show_diff,
                  actions=actions, actions_minimal=actions_minimal,
                  whiteboard_form=forms.WhiteboardForm(instance=addon),
                  user_changes=user_changes_log,
                  unlisted=not addon.is_listed)

    return render(request, 'editors/review.html', ctx)
Example #52
0
 def license_url(self, impala=False):
     return reverse('addons.license', args=[self.addon.slug, self.version])
Example #53
0
def send_mail(subject,
              message,
              from_email=None,
              recipient_list=None,
              use_deny_list=True,
              perm_setting=None,
              manage_url=None,
              headers=None,
              cc=None,
              real_email=False,
              html_message=None,
              attachments=None,
              max_retries=3,
              reply_to=None):
    """
    A wrapper around django.core.mail.EmailMessage.

    Adds deny checking and error logging.
    """
    from olympia.amo.templatetags.jinja_helpers import absolutify
    from olympia.amo.tasks import send_email
    from olympia.users import notifications

    if not recipient_list:
        return True

    if isinstance(recipient_list, six.string_types):
        raise ValueError('recipient_list should be a list, not a string.')

    # Check against user notification settings
    if perm_setting:
        if isinstance(perm_setting, six.string_types):
            perm_setting = notifications.NOTIFICATIONS_BY_SHORT[perm_setting]
        perms = dict(
            UserNotification.objects.filter(
                user__email__in=recipient_list,
                notification_id=perm_setting.id).values_list(
                    'user__email', 'enabled'))

        d = perm_setting.default_checked
        recipient_list = [
            e for e in recipient_list if e and perms.setdefault(e, d)
        ]

    # Prune denied emails.
    if use_deny_list:
        white_list = []
        for email in recipient_list:
            if email and email.lower() in settings.EMAIL_DENY_LIST:
                log.debug('Blacklisted email removed from list: %s' % email)
            else:
                white_list.append(email)
    else:
        white_list = recipient_list

    if not from_email:
        from_email = settings.DEFAULT_FROM_EMAIL

    if cc:
        # If not six.string_types, assume it is already a list.
        if isinstance(cc, six.string_types):
            cc = [cc]

    if not headers:
        headers = {}

    # Avoid auto-replies per rfc 3834 and the Microsoft variant
    headers['X-Auto-Response-Suppress'] = 'RN, NRN, OOF, AutoReply'
    headers['Auto-Submitted'] = 'auto-generated'

    def send(recipients, message, **options):
        kwargs = {
            'attachments': attachments,
            'cc': cc,
            'from_email': from_email,
            'headers': headers,
            'html_message': html_message,
            'max_retries': max_retries,
            'real_email': real_email,
            'reply_to': reply_to,
        }
        kwargs.update(options)
        # Email subject *must not* contain newlines
        args = (list(recipients), ' '.join(subject.splitlines()), message)
        return send_email.delay(*args, **kwargs)

    if white_list:
        if perm_setting:
            html_template = loader.get_template('amo/emails/unsubscribe.html')
            text_template = loader.get_template('amo/emails/unsubscribe.ltxt')
            if not manage_url:
                manage_url = urlparams(
                    absolutify(reverse('users.edit', add_prefix=False)),
                    'acct-notify')
            for recipient in white_list:
                # Add unsubscribe link to footer.
                token, hash = UnsubscribeCode.create(recipient)
                unsubscribe_url = absolutify(
                    reverse('users.unsubscribe',
                            args=[token, hash, perm_setting.short],
                            add_prefix=False))

                context = {
                    'message': message,
                    'manage_url': manage_url,
                    'unsubscribe_url': unsubscribe_url,
                    'perm_setting': perm_setting.label,
                    'SITE_URL': settings.SITE_URL,
                    'mandatory': perm_setting.mandatory,
                }
                # Render this template in the default locale until
                # bug 635840 is fixed.
                with translation.override(settings.LANGUAGE_CODE):
                    message_with_unsubscribe = text_template.render(context)

                if html_message:
                    context['message'] = html_message
                    with translation.override(settings.LANGUAGE_CODE):
                        html_with_unsubscribe = html_template.render(context)
                        result = send([recipient],
                                      message_with_unsubscribe,
                                      html_message=html_with_unsubscribe,
                                      attachments=attachments)
                else:
                    result = send([recipient],
                                  message_with_unsubscribe,
                                  attachments=attachments)
        else:
            result = send(recipient_list,
                          message=message,
                          html_message=html_message,
                          attachments=attachments)
    else:
        result = True

    return result
Example #54
0
 def setUp(self):
     super(TestThemeQueueRereview, self).setUp()
     self.status = amo.STATUS_PUBLIC
     self.rereview = True
     self.queue_url = reverse('reviewers.themes.queue_rereview')
 def test_no_django_debug_toolbar(self):
     with self.settings(DEBUG=False):
         res = self.client.get(reverse('home'), follow=True)
         assert 'djDebug' not in res.content
         assert 'debug_toolbar' not in res.content
Example #56
0
 def get_url_path(self):
     if self.channel == amo.RELEASE_CHANNEL_UNLISTED:
         return ''
     return reverse('addons.versions', args=[self.addon.slug, self.version])
Example #57
0
def unlisted_queue(request):
    return redirect(reverse('editors.unlisted_queue_pending'))
Example #58
0
 def test_eula_with_contrib_roadblock(self):
     url = reverse('addons.eula', args=[11730, 53612])
     response = self.client.get(url, follow=True)
     doc = PyQuery(response.content)
     assert doc('[data-search]').attr('class') == 'install '
Example #59
0
 def get_validation_url(self, obj):
     return reverse('devhub.file_validation',
                    args=[obj.addon.slug, obj.current_file.id])
Example #60
0
 def test_theme_list(self):
     self.create_and_become_reviewer()
     self.theme_factory()
     res = self.client.get(reverse('reviewers.themes.list'))
     assert res.status_code == 200
     assert pq(res.content)('#addon-queue tbody tr').length == 1