class ProductVersionView(ListView): template_name = 'security/product-advisories.html' context_object_name = 'product_versions' allow_empty = False @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(ProductVersionView, self).dispatch(request, *args, **kwargs) def get_queryset(self): slug = u'{product}-{version}'.format(**self.kwargs) qfilter = Q(slug__startswith=slug + '.') dots = slug.count('.') if dots < 2: # add exact match if not point release if slug.endswith('.0'): # stip trailing .0 as products are stored without them slug = slug[:-2] qfilter |= Q(slug__exact=slug) versions = Product.objects.filter(qfilter) return sorted(versions, reverse=True) def get_context_data(self, **kwargs): cxt = super(ProductVersionView, self).get_context_data(**kwargs) prod_name, version = self.kwargs['product'], self.kwargs['version'] cxt['is_obsolete'] = product_is_obsolete(prod_name, version) cxt['product_name'] = '{0} {1}'.format(cxt['product_versions'][0].product, version) cxt['product_slug'] = prod_name return cxt
class CachedRedirectView(RedirectView): permanent = True @method_decorator(cache_control_expires(24 * 30)) # 30 days def dispatch(self, request, *args, **kwargs): return super(CachedRedirectView, self).dispatch(request, *args, **kwargs)
class ProductView(ListView): template_name = 'security/product-advisories.html' context_object_name = 'product_versions' allow_empty = False minimum_versions = { 'firefox': Version('4.0'), 'thunderbird': Version('6.0'), 'seamonkey': Version('2.3'), } @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(ProductView, self).dispatch(request, *args, **kwargs) def get_queryset(self): product_slug = self.kwargs.get('slug') versions = Product.objects.filter(product_slug=product_slug) min_version = self.minimum_versions.get(product_slug) if min_version: versions = [vers for vers in versions if vers.version >= min_version] return sorted(versions, reverse=True) def get_context_data(self, **kwargs): cxt = super(ProductView, self).get_context_data(**kwargs) cxt['product_name'] = cxt['product_versions'][0].product return cxt
class AdvisoryView(DetailView): model = SecurityAdvisory template_name = 'security/advisory.html' context_object_name = 'advisory' @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(AdvisoryView, self).dispatch(request, *args, **kwargs)
class AdvisoriesView(ListView): template_name = 'security/advisories.html' queryset = SecurityAdvisory.objects.only('id', 'impact', 'title', 'announced') context_object_name = 'advisories' @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(AdvisoriesView, self).dispatch(request, *args, **kwargs)
class ProductVersionView(ListView): template_name = 'security/product-advisories.html' context_object_name = 'product_versions' allow_empty = False @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(ProductVersionView, self).dispatch(request, *args, **kwargs) def get_queryset(self): slug = self.kwargs['slug'] qfilter = Q(slug__startswith=slug + '.') dots = slug.count('.') if dots == 1: # minor version. add exact match. qfilter |= Q(slug__exact=slug) versions = Product.objects.filter(qfilter) return sorted(versions, reverse=True)
class ProductVersionView(ListView): template_name = 'security/product-advisories.html' context_object_name = 'product_versions' allow_empty = False @method_decorator(cache_control_expires(0.5)) @method_decorator(last_modified(latest_advisory)) def dispatch(self, request, *args, **kwargs): return super(ProductVersionView, self).dispatch(request, *args, **kwargs) def get_queryset(self): slug = self.kwargs['slug'] qfilter = Q(slug__startswith=slug + '.') dots = slug.count('.') if dots < 2: # add exact match if not point release if slug.endswith('.0'): # stip trailing .0 as products are stored without them slug = slug[:-2] qfilter |= Q(slug__exact=slug) versions = Product.objects.filter(qfilter) return sorted(versions, reverse=True)
# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. from django.utils.decorators import method_decorator from django.views.generic import TemplateView from bedrock.mozorg.decorators import cache_control_expires from bedrock.sitemaps.models import NO_LOCALE, SitemapURL @method_decorator(cache_control_expires(1), name="dispatch") class SitemapView(TemplateView): content_type = "text/xml" def _get_locale(self): if self.kwargs["is_none"]: # is_none here refers to the sitemap_none.xml URL. the value of that kwarg # when on that URL will be "_none" and will be None if not on that URL. # For that page we set the locale to the special value as that is what the entries # in the DB have recorded for locale for URLs that don't have a locale. locale = NO_LOCALE else: # can come back as empty string # should be None here if not a real locale because # None will mean that we should show the index of sitemaps # instead of a sitemap for a locale. locale = getattr(self.request, "locale", None) return locale
def redirect(pattern, to, permanent=True, locale_prefix=True, anchor=None, name=None, query=None, vary=None, cache_timeout=12, decorators=None, re_flags=None, to_args=None, to_kwargs=None, prepend_locale=True, merge_query=False): """ Return a url matcher suited for urlpatterns. pattern: the regex against which to match the requested URL. to: either a url name that `reverse` will find, a url that will simply be returned, or a function that will be given the request and url captures, and return the destination. permanent: boolean whether to send a 301 or 302 response. locale_prefix: automatically prepend `pattern` with a regex for an optional locale in the url. This locale (or None) will show up in captured kwargs as 'locale'. anchor: if set it will be appended to the destination url after a '#'. name: if used in a `urls.py` the redirect URL will be available as the name for use in calls to `reverse()`. Does _NOT_ work if used in a `redirects.py` file. query: a dict of query params to add to the destination url. vary: if you used an HTTP header to decide where to send users you should include that header's name in the `vary` arg. cache_timeout: number of hours to cache this redirect. just sets the proper `cache-control` and `expires` headers. decorators: a callable (or list of callables) that will wrap the view used to redirect the user. equivalent to adding a decorator to any other view. re_flags: a string of any of the characters: "iLmsux". Will modify the `pattern` regex based on the documented meaning of the flags (see python re module docs). to_args: a tuple or list of args to pass to reverse if `to` is a url name. to_kwargs: a dict of keyword args to pass to reverse if `to` is a url name. prepend_locale: if true the redirect URL will be prepended with the locale from the requested URL. merge_query: merge the requested query params from the `query` arg with any query params from the request. Usage: urlpatterns = [ redirect(r'projects/$', 'mozorg.product'), redirect(r'^projects/seamonkey$', 'mozorg.product', locale_prefix=False), redirect(r'apps/$', 'https://marketplace.firefox.com'), redirect(r'firefox/$', 'firefox.new', name='firefox'), redirect(r'the/dude$', 'abides', query={'aggression': 'not_stand'}), ] """ if permanent: redirect_class = HttpResponsePermanentRedirect else: redirect_class = HttpResponseRedirect if locale_prefix: pattern = pattern.lstrip('^/') pattern = LOCALE_RE + pattern if re_flags: pattern = '(?{})'.format(re_flags) + pattern view_decorators = [] if cache_timeout is not None: view_decorators.append(cache_control_expires(cache_timeout)) if vary: if isinstance(vary, basestring): vary = [vary] view_decorators.append(vary_on_headers(*vary)) if decorators: if callable(decorators): view_decorators.append(decorators) else: view_decorators.extend(decorators) def _view(request, *args, **kwargs): # don't want to have 'None' in substitutions kwargs = {k: v or '' for k, v in kwargs.items()} args = [x or '' for x in args] # If it's a callable, call it and get the url out. if callable(to): to_value = to(request, *args, **kwargs) else: to_value = to if to_value.startswith('/') or HTTP_RE.match(to_value): redirect_url = to_value else: try: redirect_url = reverse(to_value, args=to_args, kwargs=to_kwargs) except NoReverseMatch: # Assume it's a URL redirect_url = to_value if prepend_locale and redirect_url.startswith('/') and kwargs.get('locale'): redirect_url = '/{locale}' + redirect_url.lstrip('/') # use info from url captures. if args or kwargs: redirect_url = strip_tags(force_text(redirect_url).format(*args, **kwargs)) if query: if merge_query: req_query = parse_qs(request.META.get('QUERY_STRING')) req_query.update(query) querystring = urlencode(req_query, doseq=True) else: querystring = urlencode(query, doseq=True) elif query is None: querystring = request.META.get('QUERY_STRING') else: querystring = '' if querystring: redirect_url = '?'.join([redirect_url, querystring]) if anchor: redirect_url = '#'.join([redirect_url, anchor]) if PROTOCOL_RELATIVE_RE.match(redirect_url): redirect_url = '/' + redirect_url.lstrip('/') return redirect_class(redirect_url) # Apply decorators try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(view_decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)
def redirect(pattern, to, permanent=True, locale_prefix=True, anchor=None, name=None, query=None, vary=None, cache_timeout=12, decorators=None, re_flags=None, to_args=None, to_kwargs=None, prepend_locale=True, merge_query=False): """ Return a url matcher suited for urlpatterns. pattern: the regex against which to match the requested URL. to: either a url name that `reverse` will find, a url that will simply be returned, or a function that will be given the request and url captures, and return the destination. permanent: boolean whether to send a 301 or 302 response. locale_prefix: automatically prepend `pattern` with a regex for an optional locale in the url. This locale (or None) will show up in captured kwargs as 'locale'. anchor: if set it will be appended to the destination url after a '#'. name: if used in a `urls.py` the redirect URL will be available as the name for use in calls to `reverse()`. Does _NOT_ work if used in a `redirects.py` file. query: a dict of query params to add to the destination url. vary: if you used an HTTP header to decide where to send users you should include that header's name in the `vary` arg. cache_timeout: number of hours to cache this redirect. just sets the proper `cache-control` and `expires` headers. decorators: a callable (or list of callables) that will wrap the view used to redirect the user. equivalent to adding a decorator to any other view. re_flags: a string of any of the characters: "iLmsux". Will modify the `pattern` regex based on the documented meaning of the flags (see python re module docs). to_args: a tuple or list of args to pass to reverse if `to` is a url name. to_kwargs: a dict of keyword args to pass to reverse if `to` is a url name. prepend_locale: if true the redirect URL will be prepended with the locale from the requested URL. merge_query: merge the requested query params from the `query` arg with any query params from the request. Usage: urlpatterns = [ redirect(r'projects/$', 'mozorg.product'), redirect(r'^projects/seamonkey$', 'mozorg.product', locale_prefix=False), redirect(r'apps/$', 'https://marketplace.firefox.com'), redirect(r'firefox/$', 'firefox.new', name='firefox'), redirect(r'the/dude$', 'abides', query={'aggression': 'not_stand'}), ] """ if permanent: redirect_class = HttpResponsePermanentRedirect else: redirect_class = HttpResponseRedirect if locale_prefix: pattern = pattern.lstrip('^/') pattern = LOCALE_RE + pattern if re_flags: pattern = '(?{})'.format(re_flags) + pattern view_decorators = [] if cache_timeout is not None: view_decorators.append(cache_control_expires(cache_timeout)) if vary: if isinstance(vary, basestring): vary = [vary] view_decorators.append(vary_on_headers(*vary)) if decorators: if callable(decorators): view_decorators.append(decorators) else: view_decorators.extend(decorators) def _view(request, *args, **kwargs): # don't want to have 'None' in substitutions kwargs = {k: v or '' for k, v in kwargs.items()} args = [x or '' for x in args] # If it's a callable, call it and get the url out. if callable(to): to_value = to(request, *args, **kwargs) else: to_value = to if to_value.startswith('/') or HTTP_RE.match(to_value): redirect_url = to_value else: try: redirect_url = reverse(to_value, args=to_args, kwargs=to_kwargs) except NoReverseMatch: # Assume it's a URL redirect_url = to_value if prepend_locale and redirect_url.startswith('/') and kwargs.get('locale'): redirect_url = '/{locale}' + redirect_url.lstrip('/') # use info from url captures. if args or kwargs: redirect_url = strip_tags(force_text(redirect_url).format(*args, **kwargs)) if query: if merge_query: req_query = parse_qs(request.META.get('QUERY_STRING', '')) req_query.update(query) querystring = urlencode(req_query, doseq=True) else: querystring = urlencode(query, doseq=True) elif query is None: querystring = request.META.get('QUERY_STRING', '') else: querystring = '' if querystring: redirect_url = '?'.join([redirect_url, querystring]) if anchor: redirect_url = '#'.join([redirect_url, anchor]) if PROTOCOL_RELATIVE_RE.match(redirect_url): redirect_url = '/' + redirect_url.lstrip('/') return redirect_class(redirect_url) # Apply decorators try: # Decorators should be applied in reverse order so that input # can be sent in the order your would write nested decorators # e.g. dec1(dec2(_view)) -> [dec1, dec2] for decorator in reversed(view_decorators): _view = decorator(_view) except TypeError: log.exception('decorators not iterable or does not contain ' 'callable items') return url(pattern, _view, name=name)