import posixpath from django import http from django.shortcuts import get_object_or_404, redirect from django.views.decorators.cache import never_cache import caching.base as caching import commonware.log import jingo from mobility.decorators import mobile_template import waffle import amo from amo.decorators import login_required from amo.urlresolvers import reverse from amo.utils import urlparams, HttpResponseSendFile from access import acl from addons.decorators import addon_view_factory from addons.models import Addon from files.models import File from versions.models import Version # The version detail page redirects to the version within pagination, so we # need to enforce the number of versions per page. PER_PAGE = 30 addon_view = addon_view_factory(Addon.objects.valid) log = commonware.log.getLogger('z.versions') @addon_view @mobile_template('versions/{mobile/}version_list.html') def version_list(request, addon, template): qs = (addon.versions.filter(files__status__in=amo.VALID_STATUSES) .distinct().order_by('-created')) versions = amo.utils.paginate(request, qs, PER_PAGE) versions.object_list = list(versions.object_list) Version.transformer(versions.object_list) return jingo.render(request, template, {'addon': addon, 'versions': versions}) @addon_view def version_detail(request, addon, version_num): qs = (addon.versions.filter(files__status__in=amo.VALID_STATUSES) .distinct().order_by('-created')) # Use cached_with since values_list won't be cached. f = lambda: _find_version_page(qs, addon, version_num) return caching.cached_with(qs, f, 'vd:%s:%s' % (addon.id, version_num)) 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 return redirect(urlparams(url, 'version-%s' % version_num, page=page)) else: raise http.Http404() @never_cache @login_required def download_watermarked(request, file_id): if not waffle.switch_is_active('marketplace'): raise http.Http404() file = get_object_or_404(File.objects, pk=file_id) addon = get_object_or_404(Addon.objects, pk=file.version.addon_id) # TODO(andym): assert payment went through here? if (not addon.is_premium() or addon.is_disabled or file.status == amo.STATUS_DISABLED): raise http.Http404() dest = file.watermark(request.amo_user) if not dest: # TODO(andym): the watermarking is already in progress and we've # got multiple requests from the same users for the same file # perhaps this should go into a loop. log.debug('Watermark already in progress: %s' % file_id) raise http.Http404() log.debug('Serving watermarked file for: %s' % file_id) return HttpResponseSendFile(request, dest, content_type='application/xp-install') # Should accept junk at the end for filename goodness. def download_file(request, file_id, type=None): file = get_object_or_404(File.objects, pk=file_id) addon = get_object_or_404(Addon.objects, pk=file.version.addon_id) if addon.is_premium(): return http.HttpResponseForbidden() if addon.is_disabled or file.status == amo.STATUS_DISABLED: if acl.check_addon_ownership(request, addon, viewer=True, ignore_disabled=True): return HttpResponseSendFile(request, file.guarded_file_path, content_type='application/xp-install') else: raise http.Http404() attachment = (type == 'attachment' or not request.APP.browser) loc = file.get_mirror(addon, attachment=attachment) response = http.HttpResponseRedirect(loc) response['X-Target-Digest'] = file.hash return response guard = lambda: Addon.objects.filter(_current_version__isnull=False) @addon_view_factory(guard) def download_latest(request, addon, type='xpi', platform=None): if addon.is_premium(): return http.HttpResponseForbidden() platforms = [amo.PLATFORM_ALL.id] if platform is not None and int(platform) in amo.PLATFORMS: platforms.append(int(platform)) files = File.objects.filter(platform__in=platforms, version=addon._current_version_id) try: # If there's a file matching our platform, it'll float to the end. file = sorted(files, key=lambda f: f.platform_id == platforms[-1])[-1] except IndexError: raise http.Http404() args = [file.id, type] if type else [file.id] url = posixpath.join(reverse('downloads.file', args=args), file.filename) if request.GET: url += '?' + request.GET.urlencode() return redirect(url)