Beispiel #1
0
 def preview_as_dict(preview, src):
     d = {
         'full': urlparams(preview.image_url, src=src),
         'thumbnail': urlparams(preview.thumbnail_url, src=src),
         'caption': unicode(preview.caption)
     }
     return d
Beispiel #2
0
 def test_collection_directory_redirects(self):
     base = reverse('collections.list')
     tests = [
         ('/collections/editors_picks', 301, urlparams(base,
                                                       sort='featured')),
         ('/collections/popular/', 301, urlparams(base, sort='popular')),
         # These don't work without a login.
         ('/collections/favorites/', 301, base),
     ]
     for test in tests:
         self.check_response(*test)
 def test_collection_directory_redirects(self):
     base = reverse('collections.list')
     tests = [
         ('/collections/editors_picks', 301,
          urlparams(base, sort='featured')),
         ('/collections/popular/', 301,
          urlparams(base, sort='popular')),
         # These don't work without a login.
         ('/collections/favorites/', 301, base),
     ]
     for test in tests:
         self.check_response(*test)
Beispiel #4
0
 def get_fxa_edit_email_url(self, user):
     base_url = '{}/settings'.format(
         settings.FXA_CONFIG['default']['content_host'])
     return urlparams(base_url,
                      uid=user.fxa_id,
                      email=user.email,
                      entrypoint='addons')
Beispiel #5
0
def download_file(request, file_id, type=None, file_=None, addon=None):
    """
    Download given file.

    `addon` and `file_` parameters can be passed to avoid the database query.

    If the file is disabled or belongs to an unlisted version, requires an
    add-on developer or appropriate reviewer for the channel. If the file is
    deleted or belongs to a deleted version or add-on, reviewers can still
    access but developers can't.
    """
    def is_appropriate_reviewer(addon, channel):
        return (acl.is_reviewer(request, addon)
                if channel == amo.RELEASE_CHANNEL_LISTED else
                acl.check_unlisted_addons_reviewer(request))

    if not file_:
        file_ = get_object_or_404(File.objects, pk=file_id)
    if not addon:
        # Include deleted add-ons in the queryset, we'll check for that below.
        addon = get_object_or_404(Addon.unfiltered, pk=file_.version.addon_id)
    version = file_.version
    channel = version.channel

    if version.deleted or addon.is_deleted:
        # Only the appropriate reviewer can see deleted things.
        use_cdn = False
        has_permission = is_appropriate_reviewer(addon, channel)
    elif (addon.is_disabled or file_.status == amo.STATUS_DISABLED
          or channel == amo.RELEASE_CHANNEL_UNLISTED):
        # Only the appropriate reviewer or developers of the add-on can see
        # disabled or unlisted things.
        use_cdn = False
        has_permission = (is_appropriate_reviewer(addon, channel)
                          or acl.check_addon_ownership(
                              request, addon, dev=True, ignore_disabled=True))
    else:
        # Everyone can see public things, and we can use the CDN in that case.
        use_cdn = True
        has_permission = True

    if not has_permission:
        log.info('download file {file_id}: addon/version/file not public and '
                 'user {user_id} does not have relevant permissions.'.format(
                     file_id=file_id, user_id=request.user.pk))
        raise http.Http404()  # Not owner or admin.

    if use_cdn:
        attachment = bool(type == 'attachment')
        loc = urlparams(file_.get_file_cdn_url(attachment=attachment),
                        filehash=file_.hash)
        response = http.HttpResponseRedirect(loc)
        response['X-Target-Digest'] = file_.hash
    else:
        response = HttpResponseXSendFile(
            request,
            file_.current_file_path,
            content_type='application/x-xpinstall')
    response['Access-Control-Allow-Origin'] = '*'
    return response
Beispiel #6
0
 def test_newest_sort(self):
     r = self.client.get(urlparams(self.url, sort='created'))
     sel = pq(r.content)('#sorter ul > li.selected')
     assert sel.find('a').attr('class') == 'opt'
     assert sel.text() == 'Newest'
     c = r.context['collections'].object_list
     assert list(c) == sorted(c, key=lambda x: x.created, reverse=True)
Beispiel #7
0
 def test_normal(self):
     func = decorators.login_required(self.f)
     response = func(self.request)
     assert not self.f.called
     assert response.status_code == 302
     assert response['Location'] == (urlparams(reverse('users.login'),
                                               to='/path'))
Beispiel #8
0
 def test_updated_sort(self):
     r = self.client.get(urlparams(self.url, sort='updated'))
     sel = pq(r.content)('#sorter ul > li.selected')
     assert sel.find('a').attr('class') == 'extra-opt'
     assert sel.text() == 'Recently Updated'
     c = r.context['collections'].object_list
     assert list(c) == sorted(c, key=lambda x: x.modified, reverse=True)
Beispiel #9
0
 def test_name_sort(self):
     r = self.client.get(urlparams(self.url, sort='name'))
     sel = pq(r.content)('#sorter ul > li.selected')
     assert sel.find('a').attr('class') == 'extra-opt'
     assert sel.text() == 'Name'
     c = r.context['collections'].object_list
     assert list(c) == sorted(c, key=lambda x: x.name)
 def test_mostsubscribers_sort(self):
     r = self.client.get(urlparams(self.url, sort='followers'))
     sel = pq(r.content)('#sorter ul > li.selected')
     eq_(sel.find('a').attr('class'), 'opt')
     eq_(sel.text(), 'Most Followers')
     c = r.context['collections'].object_list
     eq_(list(c), sorted(c, key=lambda x: x.subscribers, reverse=True))
 def test_normal(self):
     func = decorators.login_required(self.f)
     response = func(self.request)
     assert not self.f.called
     assert response.status_code == 302
     assert response['Location'] == (
         urlparams(reverse('users.login'), to='/path'))
Beispiel #12
0
def download_file(request, file_id, type=None, file_=None, addon=None):
    if not file_:
        file_ = get_object_or_404(File.objects, pk=file_id)
    if not addon:
        addon = get_object_or_404(Addon.with_unlisted,
                                  pk=file_.version.addon_id)

    if addon.is_disabled or file_.status == amo.STATUS_DISABLED:
        if (acl.check_addon_ownership(
                request, addon, viewer=True, ignore_disabled=True)
                or acl.check_addons_reviewer(request)):
            return HttpResponseSendFile(request,
                                        file_.guarded_file_path,
                                        content_type='application/x-xpinstall')
        log.info(u'download file {file_id}: addon/file disabled or user '
                 u'{user_id} is not an owner'.format(file_id=file_id,
                                                     user_id=request.user.pk))
        raise http.Http404()

    if not (addon.is_listed or owner_or_unlisted_reviewer(request, addon)):
        log.info(u'download file {file_id}: addon is unlisted but user '
                 u'{user_id} is not an owner'.format(file_id=file_id,
                                                     user_id=request.user.pk))
        raise http.Http404  # Not listed, not owner or admin.

    attachment = (type == 'attachment' or not request.APP.browser)

    loc = urlparams(file_.get_mirror(addon, attachment=attachment),
                    filehash=file_.hash)
    response = http.HttpResponseRedirect(loc)
    response['X-Target-Digest'] = file_.hash
    return response
Beispiel #13
0
def install(request):
    addon_id = request.GET.get('addon_id', None)
    if addon_id:
        try:
            addon_id = int(addon_id)
        except ValueError:
            addon_id = Markup.escape(addon_id)
    addon_key = request.GET.get('addon_key', None)
    addon_name = request.GET.get('addon_name', None)
    if addon_id in addons:
        addon = addons[addon_id]
    elif addon_key in addons:
        addon = addons[addon_key]
    elif addon_name and addon_id:
        xpi = prefix('/en-US/firefox/downloads/latest/%s') % addon_id
        icon = prefix('/en-US/firefox/images/addon_icon/%s') % addon_id
        addon = {'name': addon_name, 'xpi': xpi, 'icon': icon}
    else:
        return HttpResponseNotFound()
    addon_link = addon.get('link', None)
    if addon_link:
        return HttpResponsePermanentRedirect(addon_link)
    if 'xpi' not in addon:
        return HttpResponseNotFound()
    src = request.GET.get('src', 'installservice')
    addon['xpi'] = urlparams(addon['xpi'], src=src)
    addon_params = {'URL': addon['xpi']}
    if 'icon' in addon:
        addon_params['IconURL'] = addon['icon']
    if 'hash' in addon:
        addon_params['Hash'] = addon['hash']
    referrers = ' || '.join(addon.get('referrers', default_referrers))
    return render(request, 'services/install.html',
                  {'referrers': referrers, 'addon': addon,
                   'params': json.dumps({'name': addon_params})})
 def test_name_sort(self):
     r = self.client.get(urlparams(self.url, sort='name'))
     sel = pq(r.content)('#sorter ul > li.selected')
     eq_(sel.find('a').attr('class'), 'extra-opt')
     eq_(sel.text(), 'Name')
     c = r.context['collections'].object_list
     eq_(list(c), sorted(c, key=lambda x: x.name))
 def test_newest_sort(self):
     r = self.client.get(urlparams(self.url, sort='created'))
     sel = pq(r.content)('#sorter ul > li.selected')
     eq_(sel.find('a').attr('class'), 'opt')
     eq_(sel.text(), 'Newest')
     c = r.context['collections'].object_list
     eq_(list(c), sorted(c, key=lambda x: x.created, reverse=True))
 def test_updated_sort(self):
     r = self.client.get(urlparams(self.url, sort='updated'))
     sel = pq(r.content)('#sorter ul > li.selected')
     eq_(sel.find('a').attr('class'), 'extra-opt')
     eq_(sel.text(), 'Recently Updated')
     c = r.context['collections'].object_list
     eq_(list(c), sorted(c, key=lambda x: x.modified, reverse=True))
Beispiel #17
0
def download_file(request, file_id, type=None, file_=None, addon=None):
    if not file_:
        file_ = get_object_or_404(File.objects, pk=file_id)
    if not addon:
        addon = get_object_or_404(Addon.with_unlisted, pk=file_.version.addon_id)

    if addon.is_disabled or file_.status == amo.STATUS_DISABLED:
        if acl.check_addon_ownership(request, addon, viewer=True, ignore_disabled=True) or acl.check_addons_reviewer(
            request
        ):
            return HttpResponseSendFile(request, file_.guarded_file_path, content_type="application/x-xpinstall")
        log.info(
            u"download file {file_id}: addon/file disabled or user "
            u"{user_id} is not an owner".format(file_id=file_id, user_id=request.user.pk)
        )
        raise http.Http404()

    if not (addon.is_listed or owner_or_unlisted_reviewer(request, addon)):
        log.info(
            u"download file {file_id}: addon is unlisted but user "
            u"{user_id} is not an owner".format(file_id=file_id, user_id=request.user.pk)
        )
        raise http.Http404  # Not listed, not owner or admin.

    attachment = type == "attachment" or not request.APP.browser

    loc = urlparams(file_.get_mirror(addon, attachment=attachment), filehash=file_.hash)
    response = http.HttpResponseRedirect(loc)
    response["X-Target-Digest"] = file_.hash
    return response
Beispiel #18
0
 def test_mostsubscribers_sort(self):
     r = self.client.get(urlparams(self.url, sort='followers'))
     sel = pq(r.content)('#sorter ul > li.selected')
     assert sel.find('a').attr('class') == 'opt'
     assert sel.text() == 'Most Followers'
     c = r.context['collections'].object_list
     assert list(c) == sorted(c, key=lambda x: x.subscribers, reverse=True)
Beispiel #19
0
 def assert_served_by_host(self, response, host, file_=None):
     if not file_:
         file_ = self.file
     assert response.status_code == 302
     assert response.url == (urlparams(
         '%s%s/%s' % (host, self.addon.id, urlquote(file_.filename)),
         filehash=file_.hash))
     assert response['X-Target-Digest'] == file_.hash
 def test_popular_sort(self):
     r = self.client.get(urlparams(self.url, sort='popular'))
     sel = pq(r.content)('#sorter ul > li.selected')
     eq_(sel.find('a').attr('class'), 'extra-opt')
     eq_(sel.text(), 'Recently Popular')
     c = r.context['collections'].object_list
     eq_(list(c),
         sorted(c, key=lambda x: x.weekly_subscribers, reverse=True))
Beispiel #21
0
 def test_popular_sort(self):
     r = self.client.get(urlparams(self.url, sort='popular'))
     sel = pq(r.content)('#sorter ul > li.selected')
     assert sel.find('a').attr('class') == 'extra-opt'
     assert sel.text() == 'Recently Popular'
     c = r.context['collections'].object_list
     assert list(c) == (
         sorted(c, key=lambda x: x.weekly_subscribers, reverse=True))
Beispiel #22
0
def manage_fxa_link(context):
    user = context['user']
    base_url = '{host}/settings'.format(
        host=settings.FXA_CONFIG['default']['content_host'])
    return urlparams(base_url,
                     uid=user.fxa_id,
                     email=user.email,
                     entrypoint='addons')
Beispiel #23
0
 def create_user_url(id_, url_name='profile', src=None, args=None):
     """
     We use <username> as the slug, unless it contains gross
     characters - in which case use <id> as the slug.
     """
     from olympia.amo.utils import urlparams
     args = args or []
     url = reverse('users.%s' % url_name, args=[id_] + args)
     return urlparams(url, src=src)
Beispiel #24
0
def legacy_directory_redirects(request, page):
    sorts = {'editors_picks': 'featured', 'popular': 'popular'}
    loc = base = reverse('collections.list')
    if page in sorts:
        loc = urlparams(base, sort=sorts[page])
    elif request.user.is_authenticated:
        if page == 'mine':
            loc = reverse('collections.user', args=[request.user.username])
    return http.HttpResponseRedirect(loc)
Beispiel #25
0
 def assert_served_by_host(self, response, host, file_=None):
     if not file_:
         file_ = self.file
     assert response.status_code == 302
     assert response.url == (
         urlparams('%s%s/%s' % (
             host, self.addon.id, urlquote(file_.filename)
         ), filehash=file_.hash))
     assert response['X-Target-Digest'] == file_.hash
Beispiel #26
0
def legacy_directory_redirects(request, page):
    sorts = {'editors_picks': 'featured', 'popular': 'popular'}
    loc = base = reverse('collections.list')
    if page in sorts:
        loc = urlparams(base, sort=sorts[page])
    elif request.user.is_authenticated:
        if page == 'mine':
            loc = reverse('collections.user', args=[request.user.username])
    return http.HttpResponseRedirect(loc)
Beispiel #27
0
    def check_results(self, expected):
        """Make sure the expected addons are listed in a standard search."""
        response = self.client.get(urlparams(self.url, sort='downloads'))
        assert response.status_code == 200
        got = self.get_results(response)

        for addon in expected:
            assert addon.pk in got, '%s is not in %s' % (addon.pk, got)
        return response
Beispiel #28
0
def _find_version_page(qs, addon, version_num):
    ids = list(qs.values_list("version", flat=True))
    url = reverse("addons.versions", args=[addon.slug])
    if version_num in ids:
        page = 1 + ids.index(version_num) / PER_PAGE
        to = urlparams(url, "version-%s" % version_num, page=page)
        return http.HttpResponseRedirect(to)
    else:
        raise http.Http404()
Beispiel #29
0
def _find_version_page(qs, addon, version_num):
    ids = list(qs.values_list('version', flat=True))
    url = reverse('addons.versions', args=[addon.slug])
    if version_num in ids:
        page = 1 + ids.index(version_num) / PER_PAGE
        to = urlparams(url, 'version-%s' % version_num, page=page)
        return http.HttpResponseRedirect(to)
    else:
        raise http.Http404()
Beispiel #30
0
    def check_results(self, expected):
        """Make sure the expected addons are listed in a standard search."""
        response = self.client.get(urlparams(self.url, sort='downloads'))
        assert response.status_code == 200
        got = self.get_results(response)

        for addon in expected:
            assert addon.pk in got, '%s is not in %s' % (addon.pk, got)
        return response
Beispiel #31
0
 def assert_served_by_host(self, response, host, file_=None):
     if not file_:
         file_ = self.file
     assert response.status_code == 302
     assert response.url == (urlparams(
         f'{host}{self.addon.id}/{quote(file_.filename)}',
         filehash=file_.hash,
     ))
     assert response['X-Target-Digest'] == file_.hash
     assert response['Access-Control-Allow-Origin'] == '*'
Beispiel #32
0
def index(request, version=None):
    template = "compat/index.html"
    COMPAT = [v for v in amo.COMPAT if v["app"] == request.APP.id]
    compat_dict = dict((v["main"], v) for v in COMPAT)
    if not COMPAT:
        return render(request, template, {"results": False})
    if version not in compat_dict:
        return http.HttpResponseRedirect(reverse("compat.index", args=[COMPAT[0]["main"]]))
    qs = AppCompat.search()
    binary = None

    initial = {"appver": "%s-%s" % (request.APP.id, version), "type": "all"}
    initial.update(request.GET.items())
    form = CompatForm(initial)
    if request.GET and form.is_valid():
        if form.cleaned_data["appver"]:
            app, ver = form.cleaned_data["appver"].split("-")
            if int(app) != request.APP.id or ver != version:
                new = reverse("compat.index", args=[ver], add_prefix=False)
                url = "/%s%s" % (amo.APP_IDS[int(app)].short, new)
                type_ = form.cleaned_data["type"] or None
                return http.HttpResponseRedirect(urlparams(url, type=type_))

        if form.cleaned_data["type"] != "all":
            binary = form.cleaned_data["type"] == "binary"

    compat, app = compat_dict[version], str(request.APP.id)
    compat_queries = (
        (
            "prev",
            qs.query(
                **{
                    "top_95.%s.%s" % (app, vint(compat["previous"])): True,
                    "support.%s.max__gte" % app: vint(compat["previous"]),
                }
            ),
        ),
        ("top_95", qs.query(**{"top_95_all.%s" % app: True})),
        ("all", qs),
    )
    compat_levels = [(key, version_compat(queryset, compat, app, binary)) for key, queryset in compat_queries]
    usage_addons, usage_total = usage_stats(request, compat, app, binary)
    return render(
        request,
        template,
        {
            "version": version,
            "usage_addons": usage_addons,
            "usage_total": usage_total,
            "compat_levels": compat_levels,
            "form": form,
            "results": True,
            "show_previous": request.GET.get("previous"),
        },
    )
def cache_buster(context, url):
    if 'BUILD_ID' in context:
        build = context['BUILD_ID']
    else:
        if url.endswith('.js'):
            build = context['BUILD_ID_JS']
        elif url.endswith('.css'):
            build = context['BUILD_ID_CSS']
        else:
            build = context['BUILD_ID_IMG']
    return utils.urlparams(url, b=build)
Beispiel #34
0
def cache_buster(context, url):
    if 'BUILD_ID' in context:
        build = context['BUILD_ID']
    else:
        if url.endswith('.js'):
            build = context['BUILD_ID_JS']
        elif url.endswith('.css'):
            build = context['BUILD_ID_CSS']
        else:
            build = context['BUILD_ID_IMG']
    return utils.urlparams(url, b=build)
Beispiel #35
0
def _find_version_page(qs, addon, version_num, beta=False):
    if beta:
        url = reverse('addons.beta-versions', args=[addon.slug])
    else:
        url = reverse('addons.versions', args=[addon.slug])
    ids = list(qs.values_list('version', flat=True))
    if version_num in ids:
        page = 1 + ids.index(version_num) / PER_PAGE
        to = urlparams(url, 'version-%s' % version_num, page=page)
        return http.HttpResponseRedirect(to)
    else:
        raise http.Http404()
Beispiel #36
0
def _find_version_page(qs, addon, version_num, beta=False):
    if beta and waffle.switch_is_active('beta-versions'):
        url = reverse('addons.beta-versions', args=[addon.slug])
    else:
        url = reverse('addons.versions', args=[addon.slug])
    ids = list(qs.values_list('version', flat=True))
    if version_num in ids:
        page = 1 + ids.index(version_num) / PER_PAGE
        to = urlparams(url, 'version-%s' % version_num, page=page)
        return http.HttpResponseRedirect(to)
    else:
        raise http.Http404()
def disco_persona_preview(context, persona, size='large', linked=True,
                          extra=None, details=False, title=False,
                          caption=False, src=None):
    url = None
    if linked:
        url = reverse('discovery.addons.detail', args=[persona.addon.slug])
        url = settings.SERVICES_URL + url
        if src in ('discovery-video', 'discovery-promo', 'discovery-featured'):
            url = urlparams(url, src=src)
    return persona_preview(context, persona, size=size, linked=linked,
                           extra=extra, details=details, title=title,
                           caption=caption, url=url)
Beispiel #38
0
def render_error(request, error, next_path=None, format=None):
    if format == "json":
        status = ERROR_STATUSES.get(error, 422)
        return Response({"error": error}, status=status)
    else:
        if not is_safe_url(next_path):
            next_path = None
        messages.error(request, fxa_error_message(LOGIN_ERROR_MESSAGES[error]), extra_tags="fxa")
        if request.user.is_authenticated():
            redirect_view = "users.migrate"
        else:
            redirect_view = "users.login"
        return HttpResponseRedirect(urlparams(reverse(redirect_view), to=next_path))
Beispiel #39
0
 def create_user_url(id_, username=None, url_name='profile', src=None,
                     args=None):
     """
     We use <username> as the slug, unless it contains gross
     characters - in which case use <id> as the slug.
     """
     from olympia.amo.utils import urlparams
     chars = '/<>"\''
     if not username or any(x in chars for x in username):
         username = id_
     args = args or []
     url = reverse('users.%s' % url_name, args=[username] + args)
     return urlparams(url, src=src)
Beispiel #40
0
def render_error(request, error, next_path=None, format=None):
    if format == 'json':
        status = ERROR_STATUSES.get(error, 422)
        return Response({'error': error}, status=status)
    else:
        if not is_safe_url(next_path):
            next_path = None
        messages.error(request,
                       fxa_error_message(LOGIN_ERROR_MESSAGES[error]),
                       extra_tags='fxa')
        redirect_view = 'users.login'
        return HttpResponseRedirect(
            urlparams(reverse(redirect_view), to=next_path))
Beispiel #41
0
 def check_results(self, q, expected):
     res = self.client.get(urlparams(self.url, q=q))
     assert res.status_code == 200
     content = json.loads(res.content)
     assert len(content) == len(expected)
     ids = [int(c['value']) for c in content]
     emails = [u'%s' % c['label'] for c in content]
     for d in expected:
         id = d['value']
         email = u'%s' % d['label']
         assert id in ids, ('Expected user ID "%s" not found' % id)
         assert email in emails, ('Expected username "%s" not found' %
                                  email)
Beispiel #42
0
def render_error(request, error, next_path=None, format=None):
    if format == 'json':
        status = ERROR_STATUSES.get(error, 422)
        return Response({'error': error}, status=status)
    else:
        if not is_safe_url(next_path):
            next_path = None
        messages.error(
            request, fxa_error_message(LOGIN_ERROR_MESSAGES[error]),
            extra_tags='fxa')
        redirect_view = 'users.login'
        return HttpResponseRedirect(
            urlparams(reverse(redirect_view), to=next_path))
Beispiel #43
0
 def get_user_url(self, name='profile', src=None, args=None):
     """
     We use <username> as the slug, unless it contains gross
     characters - in which case use <id> as the slug.
     """
     from olympia.amo.utils import urlparams
     chars = '/<>"\''
     slug = self.username
     if not self.username or any(x in chars for x in self.username):
         slug = self.id
     args = args or []
     url = reverse('users.%s' % name, args=[slug] + args)
     return urlparams(url, src=src)
Beispiel #44
0
 def create_user_url(id_, username=None, url_name='profile', src=None,
                     args=None):
     """
     We use <username> as the slug, unless it contains gross
     characters - in which case use <id> as the slug.
     """
     from olympia.amo.utils import urlparams
     chars = '/<>"\''
     if not username or any(x in chars for x in username):
         username = id_
     args = args or []
     url = reverse('users.%s' % url_name, args=[username] + args)
     return urlparams(url, src=src)
Beispiel #45
0
 def get_user_url(self, name='profile', src=None, args=None):
     """
     We use <username> as the slug, unless it contains gross
     characters - in which case use <id> as the slug.
     """
     from olympia.amo.utils import urlparams
     chars = '/<>"\''
     slug = self.username
     if not self.username or any(x in chars for x in self.username):
         slug = self.id
     args = args or []
     url = reverse('users.%s' % name, args=[slug] + args)
     return urlparams(url, src=src)
Beispiel #46
0
def index(request, version=None):
    template = 'compat/index.html'
    COMPAT = [v for v in amo.COMPAT if v['app'] == request.APP.id]
    compat_dict = dict((v['main'], v) for v in COMPAT)
    if not COMPAT:
        return render(request, template, {'results': False})
    if version not in compat_dict:
        return http.HttpResponseRedirect(
            reverse('compat.index', args=[COMPAT[0]['main']]))
    qs = AppCompat.search()
    binary = None

    initial = {'appver': '%s-%s' % (request.APP.id, version), 'type': 'all'}
    initial.update(request.GET.items())
    form = CompatForm(initial)
    if request.GET and form.is_valid():
        if form.cleaned_data['appver']:
            app, ver = form.cleaned_data['appver'].split('-')
            if int(app) != request.APP.id or ver != version:
                new = reverse('compat.index', args=[ver], add_prefix=False)
                url = '/%s%s' % (amo.APP_IDS[int(app)].short, new)
                type_ = form.cleaned_data['type'] or None
                return http.HttpResponseRedirect(urlparams(url, type=type_))

        if form.cleaned_data['type'] != 'all':
            binary = form.cleaned_data['type'] == 'binary'

    compat, app = compat_dict[version], str(request.APP.id)
    compat_queries = (
        ('prev',
         qs.query(
             **{
                 'top_95.%s.%s' % (app, vint(compat['previous'])): True,
                 'support.%s.max__gte' % app: vint(compat['previous'])
             })),
        ('top_95', qs.query(**{'top_95_all.%s' % app: True})),
        ('all', qs),
    )
    compat_levels = [(key, version_compat(queryset, compat, app, binary))
                     for key, queryset in compat_queries]
    usage_addons, usage_total = usage_stats(request, compat, app, binary)
    return render(
        request, template, {
            'version': version,
            'usage_addons': usage_addons,
            'usage_total': usage_total,
            'compat_levels': compat_levels,
            'form': form,
            'results': True,
            'show_previous': request.GET.get('previous')
        })
Beispiel #47
0
 def check_results(self, q, expected):
     res = self.client.get(urlparams(self.url, q=q))
     assert res.status_code == 200
     content = json.loads(res.content)
     assert len(content) == len(expected)
     ids = [int(c['value']) for c in content]
     emails = [u'%s' % c['label'] for c in content]
     for d in expected:
         id = d['value']
         email = u'%s' % d['label']
         assert id in ids, (
             'Expected user ID "%s" not found' % id)
         assert email in emails, (
             'Expected username "%s" not found' % email)
Beispiel #48
0
    def add_root_elements(self, handler):
        # set feed_url to current page
        page = None if self.page.number == 1 else self.page.number
        self.feed['feed_url'] = urlparams(self.feed['feed_url'], page=page)
        DefaultFeed.add_root_elements(self, handler)

        # http://tools.ietf.org/html/rfc5005#section-3
        self.add_page_relation(handler, 'first', 1)
        if self.page.has_previous():
            self.add_page_relation(handler, 'previous',
                                   self.page.previous_page_number())
        if self.page.has_next():
            self.add_page_relation(handler, 'next',
                                   self.page.next_page_number())
        self.add_page_relation(handler, 'last', self.page.paginator.num_pages)
Beispiel #49
0
    def add_root_elements(self, handler):
        # set feed_url to current page
        page = None if self.page.number == 1 else self.page.number
        self.feed['feed_url'] = urlparams(self.feed['feed_url'], page=page)
        DefaultFeed.add_root_elements(self, handler)

        # http://tools.ietf.org/html/rfc5005#section-3
        self.add_page_relation(handler, 'first', 1)
        if self.page.has_previous():
            self.add_page_relation(handler, 'previous',
                                   self.page.previous_page_number())
        if self.page.has_next():
            self.add_page_relation(handler, 'next',
                                   self.page.next_page_number())
        self.add_page_relation(handler, 'last', self.page.paginator.num_pages)
Beispiel #50
0
def download_file(request, file_id, type=None, file_=None, addon=None):
    def is_appropriate_reviewer(addon, channel):
        return (acl.is_reviewer(request, addon)
                if channel == amo.RELEASE_CHANNEL_LISTED
                else acl.check_unlisted_addons_reviewer(request))

    if not file_:
        file_ = get_object_or_404(File.objects, pk=file_id)
    if not addon:
        addon = get_object_or_404(Addon.objects,
                                  pk=file_.version.addon_id)
    channel = file_.version.channel

    if addon.is_disabled or file_.status == amo.STATUS_DISABLED:
        if (is_appropriate_reviewer(addon, channel) or
                acl.check_addon_ownership(
                    request, addon, dev=True, ignore_disabled=True)):
            return HttpResponseSendFile(
                request, file_.guarded_file_path,
                content_type='application/x-xpinstall')
        else:
            log.info(
                u'download file {file_id}: addon/file disabled and '
                u'user {user_id} is not an owner or reviewer.'.format(
                    file_id=file_id, user_id=request.user.pk))
            raise http.Http404()  # Not owner or admin.

    if channel == amo.RELEASE_CHANNEL_UNLISTED:
        if (acl.check_unlisted_addons_reviewer(request) or
                acl.check_addon_ownership(
                    request, addon, dev=True, ignore_disabled=True)):
            return HttpResponseSendFile(
                request, file_.file_path,
                content_type='application/x-xpinstall')
        else:
            log.info(
                u'download file {file_id}: version is unlisted and '
                u'user {user_id} is not an owner or reviewer.'.format(
                    file_id=file_id, user_id=request.user.pk))
            raise http.Http404()  # Not owner or admin.

    attachment = bool(type == 'attachment')

    loc = urlparams(file_.get_file_cdn_url(attachment=attachment),
                    filehash=file_.hash)
    response = http.HttpResponseRedirect(loc)
    response['X-Target-Digest'] = file_.hash
    return response
Beispiel #51
0
def download_file(request, file_id, type=None, file_=None, addon=None):
    def is_appropriate_reviewer(addon, channel):
        return (acl.is_reviewer(request, addon)
                if channel == amo.RELEASE_CHANNEL_LISTED
                else acl.check_unlisted_addons_reviewer(request))

    if not file_:
        file_ = get_object_or_404(File.objects, pk=file_id)
    if not addon:
        addon = get_object_or_404(Addon.objects,
                                  pk=file_.version.addon_id)
    channel = file_.version.channel

    if addon.is_disabled or file_.status == amo.STATUS_DISABLED:
        if (is_appropriate_reviewer(addon, channel) or
                acl.check_addon_ownership(
                    request, addon, dev=True, ignore_disabled=True)):
            return HttpResponseSendFile(
                request, file_.guarded_file_path,
                content_type='application/x-xpinstall')
        else:
            log.info(
                u'download file {file_id}: addon/file disabled and '
                u'user {user_id} is not an owner or reviewer.'.format(
                    file_id=file_id, user_id=request.user.pk))
            raise http.Http404()  # Not owner or admin.

    if channel == amo.RELEASE_CHANNEL_UNLISTED:
        if (acl.check_unlisted_addons_reviewer(request) or
                acl.check_addon_ownership(
                    request, addon, dev=True, ignore_disabled=True)):
            return HttpResponseSendFile(
                request, file_.file_path,
                content_type='application/x-xpinstall')
        else:
            log.info(
                u'download file {file_id}: version is unlisted and '
                u'user {user_id} is not an owner or reviewer.'.format(
                    file_id=file_id, user_id=request.user.pk))
            raise http.Http404()  # Not owner or admin.

    attachment = (type == 'attachment' or not request.APP.browser)

    loc = urlparams(file_.get_file_cdn_url(attachment=attachment),
                    filehash=file_.hash)
    response = http.HttpResponseRedirect(loc)
    response['X-Target-Digest'] = file_.hash
    return response
Beispiel #52
0
    def test_download_view(self):
        """Regular listed files are served through the CDN"""
        addon = addon_factory()
        file_ = addon.current_version.all_files[0]
        user = user_factory()
        self.grant_permission(user, 'Admin:Tools')
        self.client.login(email=user.email)

        download_url = reverse('admin:files_file_download', args=(file_.pk, ))
        response = self.client.get(download_url, follow=False)
        assert response.status_code == 302

        path = user_media_url('addons')

        assert response.url == (urlparams(
            '%s%s/%s' % (path, addon.id, urlquote(file_.filename)),
            filehash=file_.hash))
        assert response['X-Target-Digest'] == file_.hash
    def test_expose_fxa_edit_email_url(self):
        fxa_host = 'http://example.com'
        user_fxa_id = 'ufxa-id-123'
        self.user.update(fxa_id=user_fxa_id)

        with override_settings(FXA_CONTENT_HOST=fxa_host):
            expected_url = urlparams('{}/settings'.format(fxa_host),
                                     uid=user_fxa_id, email=self.user_email,
                                     entrypoint='addons')

            data = super(TestUserProfileSerializer, self).test_basic()
            assert data['fxa_edit_email_url'] == expected_url

        # And to make sure it's not present in v3
        gates = {None: ('del-accounts-fxa-edit-email-url',)}
        with override_settings(DRF_API_GATES=gates):
            data = super(TestUserProfileSerializer, self).test_basic()
            assert 'fxa_edit_email_url' not in data
Beispiel #54
0
def collection_listing(request, base=None):
    sort = request.GET.get('sort')
    # We turn users into followers.
    if sort == 'users':
        return redirect(urlparams(reverse('collections.list'),
                                  sort='followers'), permanent=True)
    filter = get_filter(request, base)
    # Counts are hard to cache automatically, and accuracy for this
    # one is less important. Remember it for 5 minutes.
    countkey = hashlib.md5(str(filter.qs.query) + '_count').hexdigest()
    count = cache.get(countkey)
    if count is None:
        count = filter.qs.count()
        cache.set(countkey, count, 300)
    collections = paginate(request, filter.qs, count=count)
    return render_cat(request, 'bandwagon/impala/collection_listing.html',
                      dict(collections=collections, src='co-hc-sidebar',
                           dl_src='co-dp-sidebar', filter=filter, sort=sort,
                           sorting=filter.field))
Beispiel #55
0
def index(request, version=None):
    template = 'compat/index.html'
    COMPAT = [v for v in amo.COMPAT if v['app'] == request.APP.id]
    compat_dict = dict((v['main'], v) for v in COMPAT)
    if not COMPAT:
        return render(request, template, {'results': False})
    if version not in compat_dict:
        return http.HttpResponseRedirect(reverse('compat.index',
                                                 args=[COMPAT[0]['main']]))
    qs = AppCompat.search()
    binary = None

    initial = {'appver': '%s-%s' % (request.APP.id, version), 'type': 'all'}
    initial.update(request.GET.items())
    form = CompatForm(initial)
    if request.GET and form.is_valid():
        if form.cleaned_data['appver']:
            app, ver = form.cleaned_data['appver'].split('-')
            if int(app) != request.APP.id or ver != version:
                new = reverse('compat.index', args=[ver], add_prefix=False)
                url = '/%s%s' % (amo.APP_IDS[int(app)].short, new)
                type_ = form.cleaned_data['type'] or None
                return http.HttpResponseRedirect(urlparams(url, type=type_))

        if form.cleaned_data['type'] != 'all':
            binary = form.cleaned_data['type'] == 'binary'

    compat, app = compat_dict[version], str(request.APP.id)
    compat_queries = (
        ('prev', qs.query(**{
            'top_95.%s.%s' % (app, vint(compat['previous'])): True,
            'support.%s.max__gte' % app: vint(compat['previous'])})),
        ('top_95', qs.query(**{'top_95_all.%s' % app: True})),
        ('all', qs),
    )
    compat_levels = [(key, version_compat(queryset, compat, app, binary))
                     for key, queryset in compat_queries]
    usage_addons, usage_total = usage_stats(request, compat, app, binary)
    return render(request, template,
                  {'version': version, 'usage_addons': usage_addons,
                   'usage_total': usage_total, 'compat_levels': compat_levels,
                   'form': form, 'results': True,
                   'show_previous': request.GET.get('previous')})
Beispiel #56
0
    def test_download_view(self):
        """Regular listed files are served through the CDN"""
        addon = addon_factory()
        file_ = addon.current_version.all_files[0]
        user = user_factory()
        self.grant_permission(user, 'Admin:Tools')
        self.grant_permission(user, 'Admin:Advanced')
        self.client.login(email=user.email)

        download_url = reverse('admin:files_file_download', args=(file_.pk,))
        response = self.client.get(download_url, follow=False)
        assert response.status_code == 302

        path = user_media_url('addons')

        assert response.url == (
            urlparams('%s%s/%s' % (
                path, addon.id, urlquote(file_.filename)
            ), filehash=file_.hash))
        assert response['X-Target-Digest'] == file_.hash
Beispiel #57
0
def version_detail(request, addon, version_num):
    # TODO: Does setting this in memcachd even make sense?
    # This is specific to an add-ons version so the chance of this hitting
    # the cache and not missing seems quite bad to me (cgrebs)
    def _fetch():
        qs = _version_list_qs(addon)
        return list(qs.values_list('version', flat=True))

    cache_key = make_key(
        u'version-detail:{}:{}'.format(addon.id, version_num),
        normalize=True)

    ids = cache_get_or_set(cache_key, _fetch)

    url = reverse('addons.versions', args=[addon.slug])
    if version_num in ids:
        page = 1 + ids.index(version_num) / PER_PAGE
        to = urlparams(url, 'version-%s' % version_num, page=page)
        return http.HttpResponseRedirect(to)
    else:
        raise http.Http404()
Beispiel #58
0
    def test_expose_fxa_edit_email_url(self):
        fxa_host = 'http://example.com'
        fxa_config = {
            'default': {
                'content_host': fxa_host,
            },
        }
        user_fxa_id = 'ufxa-id-123'
        self.user.update(fxa_id=user_fxa_id)

        with override_settings(FXA_CONFIG=fxa_config):
            expected_url = urlparams('{}/settings'.format(fxa_host),
                                     uid=user_fxa_id, email=self.user_email,
                                     entrypoint='addons')

            data = super(TestUserProfileSerializer, self).test_basic()
            assert data['fxa_edit_email_url'] == expected_url

        # And to make sure it's not present in v3
        gates = {None: ('del-accounts-fxa-edit-email-url',)}
        with override_settings(DRF_API_GATES=gates):
            data = super(TestUserProfileSerializer, self).test_basic()
            assert 'fxa_edit_email_url' not in data
Beispiel #59
0
    url('^addons/versions/(\d+)/?$',
        lambda r, id: redirect('addons.versions', id, permanent=True)),

    url('^addons/versions/(\d+)/format:rss$',
        lambda r, id: redirect('addons.versions.rss', id, permanent=True)),

    # Legacy redirect. Requires a view to get extra data not provided in URL.
    url('^versions/updateInfo/(?P<version_id>\d+)',
        version_views.update_info_redirect),

    url('^addons/reviews/(\d+)/format:rss$',
        lambda r, id: redirect('addons.ratings.list.rss', id, permanent=True)),

    url('^search-engines.*$',
        lambda r: redirect(urlparams(reverse('search.search'), atype=4),
                           permanent=True)),

    url('^addons/contribute/(\d+)/?$',
        lambda r, id: redirect('addons.contribute', id, permanent=True)),

    url('^recommended$',
        lambda r: redirect(reverse('browse.extensions') + '?sort=featured',
                           permanent=True)),

    url('^recommended/format:rss$',
        lambda r: redirect('browse.featured.rss', permanent=True)),
]

if settings.DEBUG:
    # Remove leading and trailing slashes so the regex matches.