Skip to content

Commit

Permalink
Bug 894055: Add funnelcake parameter to bedrock URLs.
Browse files Browse the repository at this point in the history
Now if a page has a download button on it, and the
url includes the query param `f=[0..9999]`, then that
number will end up on download links in the form
`product=firefox-stub-f999`. The ID must be numeric
and not exceed 4 digits.
  • Loading branch information
pmac committed Jul 19, 2013
1 parent 90e5419 commit 545a285
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 11 deletions.
3 changes: 2 additions & 1 deletion bedrock/facebookapps/tests/test_utils.py
Expand Up @@ -129,8 +129,9 @@ def test_locale_remains_unchanged(self):

class TestJsRedirect(tests.TestCase):
def setUp(self):
self.request = Mock(['locale'])
self.request = Mock(['locale', 'GET'])
self.request.locale = 'en-US'
self.request.GET = {}
self.url = 'https://www.mozilla.org/'
self.response = utils.js_redirect(self.url, self.request)

Expand Down
16 changes: 16 additions & 0 deletions bedrock/mozorg/context_processors.py
Expand Up @@ -2,8 +2,24 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import re
from datetime import datetime


# match 1 - 4 digits only
FC_RE = re.compile(r'^\d{1,4}$')


def current_year(request):
return {"current_year": datetime.today().year}


def funnelcake_param(request):
"""If a query param for a funnelcake is sent, add it to the context."""
fc_id = request.GET.get('f', None)
context = {}

if fc_id and FC_RE.match(fc_id):
context['funnelcake_id'] = fc_id

return context
23 changes: 18 additions & 5 deletions bedrock/mozorg/helpers/download_buttons.py
Expand Up @@ -102,7 +102,7 @@ def make_aurora_link(product, version, platform, locale,

def make_download_link(product, build, version, platform, locale,
force_direct=False, force_full_installer=False,
force_funnelcake=False):
force_funnelcake=False, funnelcake_id=None):
# Aurora has a special download link format
if build == 'aurora':
return make_aurora_link(product, version, platform, locale,
Expand All @@ -126,6 +126,10 @@ def make_download_link(product, build, version, platform, locale,

version = ('beta-' if build == 'beta' else '') + suffix

# append funnelcake id to version if we have one
if funnelcake_id:
version = '{vers}-f{fc}'.format(vers=version, fc=funnelcake_id)

# Figure out the base url. certain locales have a transitional
# thankyou-style page (most do)
src = 'direct'
Expand Down Expand Up @@ -166,6 +170,7 @@ def download_firefox(ctx, build='release', small=False, icon=True,
alt_build = '' if build == 'release' else build
platform = 'mobile' if mobile else 'desktop'
locale = locale or ctx['request'].locale
funnelcake_id = ctx.get('funnelcake_id', False)
dom_id = dom_id or 'download-button-%s-%s' % (platform, build)

def latest(locale):
Expand Down Expand Up @@ -199,8 +204,12 @@ def latest(locale):

# And generate all the info
download_link = make_download_link(
'firefox', build, version, plat_os,
_locale, force_direct, force_full_installer, force_funnelcake)
'firefox', build, version, plat_os, _locale,
force_direct=force_direct,
force_full_installer=force_full_installer,
force_funnelcake=force_funnelcake,
funnelcake_id=funnelcake_id,
)

# If download_link_direct is False the data-direct-link attr
# will not be output, and the JS won't attempt the IE popup.
Expand All @@ -209,8 +218,12 @@ def latest(locale):
download_link_direct = False
else:
download_link_direct = make_download_link(
'firefox', build, version, plat_os,
_locale, True, force_full_installer, force_funnelcake)
'firefox', build, version, plat_os, _locale,
force_direct=True,
force_full_installer=force_full_installer,
force_funnelcake=force_funnelcake,
funnelcake_id=funnelcake_id,
)
if download_link_direct == download_link:
download_link_direct = False

Expand Down
32 changes: 32 additions & 0 deletions bedrock/mozorg/tests/test_context_processors.py
@@ -0,0 +1,32 @@
# 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 http://mozilla.org/MPL/2.0/.

from django.test.client import RequestFactory

from nose.tools import eq_

from bedrock.mozorg.context_processors import funnelcake_param
from bedrock.mozorg.tests import TestCase


class TestFunnelcakeParam(TestCase):
def setUp(self):
self.rf = RequestFactory()

def _funnelcake(self, **kwargs):
return funnelcake_param(self.rf.get('/', kwargs))

def test_funnelcake_param_noop(self):
"""Should return an empty dict normally."""
eq_(self._funnelcake(), {})

def test_funnelcake_param_f(self):
"""Should inject funnelcake into context."""
eq_(self._funnelcake(f='5'), {'funnelcake_id': '5'})
eq_(self._funnelcake(f='234'), {'funnelcake_id': '234'})

def test_funnelcake_param_bad(self):
"""Should not inject bad funnelcake into context."""
eq_(self._funnelcake(f='5dude'), {})
eq_(self._funnelcake(f='123456'), {})
25 changes: 23 additions & 2 deletions bedrock/mozorg/tests/test_helper_download_buttons.py
Expand Up @@ -15,6 +15,9 @@
from bedrock.mozorg.helpers.download_buttons import make_download_link


_ALL = settings.STUB_INSTALLER_ALL


def render(s, context={}):
t = jingo.env.from_string(s)
return t.render(context)
Expand Down Expand Up @@ -273,8 +276,7 @@ def test_stub_installer(self):
'en-US')
ok_('product=firefox-beta-stub&' in url)

@override_settings(STUB_INSTALLER_LOCALES={
'win': settings.STUB_INSTALLER_ALL})
@override_settings(STUB_INSTALLER_LOCALES={'win': _ALL})
def test_stub_installer_all(self):
"""Button should give stub for all langs when ALL is set."""
url = make_download_link('firefox', 'release', 19.0, 'os_windows',
Expand Down Expand Up @@ -305,3 +307,22 @@ def test_stub_installer_en_us_win_only(self):
url = make_download_link('firefox', 'beta', '20.0b4', 'os_windows',
'fr')
ok_('product=firefox-beta-stub&' not in url)

@override_settings(STUB_INSTALLER_LOCALES={'win': _ALL})
def test_funnelcake_id(self):
"""Button should append funnelcake ID to product in download URL."""
url = make_download_link('firefox', 'release', 19.0, 'os_windows',
'en-US', funnelcake_id='2')
ok_('product=firefox-stub-f2&' in url)

url = make_download_link('firefox', 'release', 19.0, 'os_windows',
'fr', funnelcake_id='2')
ok_('product=firefox-stub-f2&' in url)

url = make_download_link('firefox', 'release', 19.0, 'os_osx',
'de', funnelcake_id='23')
ok_('product=firefox-19.0-f23&' in url)

url = make_download_link('firefox', 'beta', '20.0b4', 'os_linux',
'es-ES', funnelcake_id='234')
ok_('product=firefox-20.0b4-f234&' in url)
24 changes: 24 additions & 0 deletions bedrock/mozorg/tests/test_views.py
Expand Up @@ -2,8 +2,10 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from django.conf import settings
from django.core import mail
from django.test.client import Client
from django.test.utils import override_settings

from captcha.fields import ReCaptchaField
from funfactory.urlresolvers import reverse
Expand All @@ -16,6 +18,9 @@
from lib import l10n_utils


_ALL = settings.STUB_INSTALLER_ALL


class TestViews(TestCase):
def setUp(self):
self.client = Client()
Expand All @@ -30,6 +35,25 @@ def test_hacks_newsletter_frames_allow(self):

ok_('x-frame-options' not in resp)

@override_settings(STUB_INSTALLER_LOCALES={'win': _ALL})
def test_download_button_funnelcake(self):
"""The download button should have the funnelcake ID."""
with self.activate('en-US'):
resp = self.client.get(reverse('mozorg.home'), {'f': '5'})
ok_('product=firefox-stub-f5&' in resp.content)

@override_settings(STUB_INSTALLER_LOCALES={'win': _ALL})
def test_download_button_bad_funnelcake(self):
"""The download button should not have a bad funnelcake ID."""
with self.activate('en-US'):
resp = self.client.get(reverse('mozorg.home'), {'f': '5dude'})
ok_('product=firefox-stub&' in resp.content)
ok_('product=firefox-stub-f5dude&' not in resp.content)

resp = self.client.get(reverse('mozorg.home'), {'f': '999999999'})
ok_('product=firefox-stub&' in resp.content)
ok_('product=firefox-stub-f999999999&' not in resp.content)


class TestUniversityAmbassadors(TestCase):
@patch.object(ReCaptchaField, 'clean', Mock())
Expand Down
7 changes: 4 additions & 3 deletions bedrock/settings/base.py
Expand Up @@ -378,7 +378,7 @@ def JINJA_CONFIG():
'js/base/mozilla-input-placeholder.js',
),
'existing': (
'js/newsletter/existing.js',
'js/newsletter/existing.js',
),
'expanders': (
'js/base/mozilla-expanders.js',
Expand Down Expand Up @@ -665,6 +665,7 @@ def JINJA_CONFIG():
'django.core.context_processors.csrf',
'django.contrib.messages.context_processors.messages',
'bedrock.mozorg.context_processors.current_year',
'bedrock.mozorg.context_processors.funnelcake_param',
'bedrock.firefox.context_processors.latest_firefox_versions',
'jingo_minify.helpers.build_ids',
))
Expand Down Expand Up @@ -703,8 +704,8 @@ def JINJA_CONFIG():

# Locales showing the 15th Anniversary slideshow on /contribute
LOCALES_WITH_MOZ15 = ['bg', 'cs', 'de', 'el', 'en-GB', 'en-US', 'es-AR', 'es-CL',
'es-ES', 'es-MX', 'fr', 'fy-NL', 'hr', 'id', 'it', 'lt',
'ms', 'nl', 'pl' ,'pt-BR', 'ru', 'sl', 'sq', 'sr', 'ta',
'es-ES', 'es-MX', 'fr', 'fy-NL', 'hr', 'id', 'it', 'lt',
'ms', 'nl', 'pl', 'pt-BR', 'ru', 'sl', 'sq', 'sr', 'ta',
'zh-CN', 'zh-TW']

# reCAPTCHA keys
Expand Down

0 comments on commit 545a285

Please sign in to comment.