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
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)
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')
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
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)
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'))
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)
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'))
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
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))
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
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)
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))
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))
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')
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)
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)
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 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)
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
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()
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()
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
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'] == '*'
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)
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)
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()
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)
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))
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)
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))
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)
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))
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)
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)
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)
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 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)
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)
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)
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
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
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
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))
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 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
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()
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
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.