зеркало из https://github.com/mozilla/bedrock.git
[fix bug 1029829][fix bug 1029838][bug 1081917] Thunderbird RNA
* Created releasenotes bedrock app * Migrated firefox release notes views to releasenotes app. * Added thunderbird releasenotes urls * Added global.conf RewriteRules for Thunderbird release notes. * Thunderbird base, release notes, system requirements templates
This commit is contained in:
Родитель
d9ed3b1b69
Коммит
1b1381e328
|
@ -1,13 +0,0 @@
|
|||
# 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/.
|
||||
|
||||
# Adapted from django-mozilla-product-details
|
||||
version_re = (r"\d+" # major (x in x.y)
|
||||
"\.\d+" # minor1 (y in x.y)
|
||||
"\.?(?:\d+)?" # minor2 (z in x.y.z)
|
||||
"\.?(?:\d+)?" # minor3 (w in x.y.z.w)
|
||||
"(?:a|b(?:eta)?)?" # alpha/beta
|
||||
"(?:\d*)" # alpha/beta version
|
||||
"(?:pre)?" # pre release
|
||||
"(?:\d)?") # pre release version
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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/.
|
||||
|
@ -450,7 +449,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_australis_29(self, render_mock):
|
||||
"""Should use australis template for 29.0."""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='29.0')
|
||||
self.view(req, version='29.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -458,7 +457,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_australis_29_0_1(self, render_mock):
|
||||
"""Should use australis template for 29.0.1"""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='29.0.1')
|
||||
self.view(req, version='29.0.1')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -466,7 +465,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_30(self, render_mock):
|
||||
"""Should use australis template for 30.0."""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='30.0')
|
||||
self.view(req, version='30.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -474,7 +473,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_31(self, render_mock):
|
||||
"""Should use australis template for 31.0."""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='31.0')
|
||||
self.view(req, version='31.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -482,7 +481,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_33_0(self, render_mock):
|
||||
"""Should use australis template for 33.0."""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='33.0')
|
||||
self.view(req, version='33.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -490,7 +489,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_33_0_1(self, render_mock):
|
||||
"""Should use australis template for 33.0.1"""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='33.0.1')
|
||||
self.view(req, version='33.0.1')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/whatsnew-no-tour.html'])
|
||||
|
||||
|
@ -498,7 +497,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_fx_33_1(self, render_mock):
|
||||
"""Should use privacy tour template for 33.1"""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/')
|
||||
self.view(req, fx_version='33.1')
|
||||
self.view(req, version='33.1')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/privacy_tour/no-tour.html'])
|
||||
|
||||
|
@ -506,7 +505,7 @@ class TestWhatsNew(TestCase):
|
|||
def test_rv_prefix(self, render_mock):
|
||||
"""Prefixed oldversion shouldn't impact version sniffing."""
|
||||
req = self.rf.get('/en-US/firefox/whatsnew/?oldversion=rv:10.0')
|
||||
self.view(req, fx_version='33.1')
|
||||
self.view(req, version='33.1')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/privacy_tour/tour.html'])
|
||||
|
||||
|
@ -516,7 +515,7 @@ class TestWhatsNew(TestCase):
|
|||
url = '/en-US/firefox/whatsnew/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp['location'], 'https://testserver' + url)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -525,7 +524,7 @@ class TestWhatsNew(TestCase):
|
|||
url = '/en-US/firefox/whatsnew/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -534,7 +533,7 @@ class TestWhatsNew(TestCase):
|
|||
url = '/en-US/firefox/whatsnew/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=True):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
|
||||
|
@ -549,7 +548,7 @@ class TestTourView(TestCase):
|
|||
def test_fx_tour_template(self, render_mock):
|
||||
"""Should use firstrun tour template"""
|
||||
req = self.rf.get('/en-US/firefox/tour/')
|
||||
self.view(req, fx_version='29.0')
|
||||
self.view(req, version='29.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/help-menu-tour.html'])
|
||||
|
||||
|
@ -557,7 +556,7 @@ class TestTourView(TestCase):
|
|||
def test_fx_dev_browser_35_0_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 35.0a2"""
|
||||
req = self.rf.get('/en-US/firefox/tour/')
|
||||
self.view(req, fx_version='35.0a2')
|
||||
self.view(req, version='35.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -565,7 +564,7 @@ class TestTourView(TestCase):
|
|||
def test_fx_dev_browser_35_1_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 35.1a2"""
|
||||
req = self.rf.get('/en-US/firefox/tour/')
|
||||
self.view(req, fx_version='35.1a2')
|
||||
self.view(req, version='35.1a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -573,7 +572,7 @@ class TestTourView(TestCase):
|
|||
def test_fx_dev_browser_36_0_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 36.0a2"""
|
||||
req = self.rf.get('/en-US/firefox/tour/')
|
||||
self.view(req, fx_version='36.0a2')
|
||||
self.view(req, version='36.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -581,7 +580,7 @@ class TestTourView(TestCase):
|
|||
def test_fx_dev_browser_34_0_a2(self, render_mock):
|
||||
"""Should use standard firstrun template for older aurora"""
|
||||
req = self.rf.get('/en-US/firefox/tour/')
|
||||
self.view(req, fx_version='34.0a2')
|
||||
self.view(req, version='34.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/help-menu-tour.html'])
|
||||
|
||||
|
@ -591,7 +590,7 @@ class TestTourView(TestCase):
|
|||
url = '/en-US/firefox/tour/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp['location'], 'https://testserver' + url)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -600,7 +599,7 @@ class TestTourView(TestCase):
|
|||
url = '/en-US/firefox/tour/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -609,7 +608,7 @@ class TestTourView(TestCase):
|
|||
url = '/en-US/firefox/tour/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=True):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
|
||||
|
@ -633,7 +632,7 @@ class TestFirstRun(TestCase):
|
|||
def test_fx_australis_29(self, render_mock):
|
||||
"""Should use firstrun tour template"""
|
||||
req = self.rf.get('/en-US/firefox/firstrun/')
|
||||
self.view(req, fx_version='29.0')
|
||||
self.view(req, version='29.0')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/firstrun-tour.html'])
|
||||
|
||||
|
@ -641,7 +640,7 @@ class TestFirstRun(TestCase):
|
|||
def test_fx_dev_browser_35_0_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 35.0a2"""
|
||||
req = self.rf.get('/en-US/firefox/firstrun/')
|
||||
self.view(req, fx_version='35.0a2')
|
||||
self.view(req, version='35.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -649,7 +648,7 @@ class TestFirstRun(TestCase):
|
|||
def test_fx_dev_browser_35_1_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 35.1a2"""
|
||||
req = self.rf.get('/en-US/firefox/firstrun/')
|
||||
self.view(req, fx_version='35.1a2')
|
||||
self.view(req, version='35.1a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -657,7 +656,7 @@ class TestFirstRun(TestCase):
|
|||
def test_fx_dev_browser_36_0_a2(self, render_mock):
|
||||
"""Should use dev browser firstrun template for 36.0a2"""
|
||||
req = self.rf.get('/en-US/firefox/firstrun/')
|
||||
self.view(req, fx_version='36.0a2')
|
||||
self.view(req, version='36.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/dev-firstrun.html'])
|
||||
|
||||
|
@ -665,7 +664,7 @@ class TestFirstRun(TestCase):
|
|||
def test_fx_dev_browser_34_0_a2(self, render_mock):
|
||||
"""Should use standard firstrun template for older aurora"""
|
||||
req = self.rf.get('/en-US/firefox/firstrun/')
|
||||
self.view(req, fx_version='34.0a2')
|
||||
self.view(req, version='34.0a2')
|
||||
template = render_mock.call_args[0][1]
|
||||
eq_(template, ['firefox/australis/firstrun-tour.html'])
|
||||
|
||||
|
@ -675,7 +674,7 @@ class TestFirstRun(TestCase):
|
|||
url = '/en-US/firefox/firstrun/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp['location'], 'https://testserver' + url)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -684,7 +683,7 @@ class TestFirstRun(TestCase):
|
|||
url = '/en-US/firefox/firstrun/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=False):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
@override_settings(DEV=True)
|
||||
|
@ -693,7 +692,7 @@ class TestFirstRun(TestCase):
|
|||
url = '/en-US/firefox/firstrun/'
|
||||
req = self.rf.get(url)
|
||||
with patch.object(req, 'is_secure', return_value=True):
|
||||
resp = self.view(req, fx_version='29.0')
|
||||
resp = self.view(req, version='29.0')
|
||||
eq_(resp.status_code, 200)
|
||||
|
||||
|
||||
|
@ -833,117 +832,3 @@ class TestWhatsnewRedirect(FxVersionRedirectsMixin, TestCase):
|
|||
# if there's no oldversion parameter, show no tour
|
||||
response = self.client.get(self.url, HTTP_USER_AGENT=self.user_agent)
|
||||
self.assertNotIn(self.expected, response.content)
|
||||
|
||||
|
||||
@patch.object(fx_views, 'firefox_details', firefox_details)
|
||||
class TestReleaseNotesIndex(TestCase):
|
||||
def test_relnotes_index(self):
|
||||
with self.activate('en-US'):
|
||||
response = self.client.get(reverse('firefox.releases.index'))
|
||||
doc = pq(response.content)
|
||||
eq_(len(doc('a[href="0.1.html"]')), 1)
|
||||
eq_(len(doc('a[href="0.10.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.0.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.0.8.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.5.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.5.0.12.html"]')), 1)
|
||||
eq_(len(doc('a[href="../2.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../2.0.0.20/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../3.6/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../3.6.28/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../17.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../17.0.11/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.1.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.1.1/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../25.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../25.0.1/releasenotes/"]')), 1)
|
||||
|
||||
|
||||
@patch.object(fx_views, 'firefox_details', firefox_details)
|
||||
@patch.object(fx_views, 'mobile_details', mobile_details)
|
||||
class TestNotesRedirects(TestCase):
|
||||
def _test(self, url_from, url_to):
|
||||
with self.activate('en-US'):
|
||||
url = '/en-US' + url_from
|
||||
response = self.client.get(url)
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['Location'], 'http://testserver/en-US' + url_to)
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_VERSION='22.0')
|
||||
def test_desktop_release_version(self):
|
||||
self._test('/firefox/notes/',
|
||||
'/firefox/22.0/releasenotes/')
|
||||
self._test('/firefox/latest/releasenotes/',
|
||||
'/firefox/22.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_DEVEL_VERSION='23.0b1')
|
||||
def test_desktop_beta_version(self):
|
||||
self._test('/firefox/beta/notes/',
|
||||
'/firefox/23.0beta/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_AURORA='24.0a2')
|
||||
def test_desktop_aurora_version(self):
|
||||
self._test('/firefox/aurora/notes/',
|
||||
'/firefox/24.0a2/auroranotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_ESR='24.2.0esr')
|
||||
def test_desktop_esr_version(self):
|
||||
self._test('/firefox/organizations/notes/',
|
||||
'/firefox/24.2.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
version='22.0')
|
||||
def test_mobile_release_version(self):
|
||||
self._test('/mobile/notes/',
|
||||
'/mobile/22.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
beta_version='23.0b1')
|
||||
def test_mobile_beta_version(self):
|
||||
self._test('/mobile/beta/notes/',
|
||||
'/mobile/23.0beta/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
alpha_version='24.0a2')
|
||||
def test_mobile_aurora_version(self):
|
||||
self._test('/mobile/aurora/notes/',
|
||||
'/mobile/24.0a2/auroranotes/')
|
||||
|
||||
|
||||
@patch.object(fx_views, 'firefox_details', firefox_details)
|
||||
class TestSysreqRedirect(TestCase):
|
||||
def _test(self, url_from, url_to):
|
||||
with self.activate('en-US'):
|
||||
url = '/en-US' + url_from
|
||||
response = self.client.get(url)
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['Location'], 'http://testserver/en-US' + url_to)
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_VERSION='22.0')
|
||||
def test_desktop_release_version(self):
|
||||
self._test('/firefox/system-requirements/',
|
||||
'/firefox/22.0/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_DEVEL_VERSION='23.0b1')
|
||||
def test_desktop_beta_version(self):
|
||||
self._test('/firefox/beta/system-requirements/',
|
||||
'/firefox/23.0beta/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_AURORA='24.0a2')
|
||||
def test_desktop_aurora_version(self):
|
||||
self._test('/firefox/aurora/system-requirements/',
|
||||
'/firefox/24.0a2/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_ESR='24.2.0esr')
|
||||
def test_desktop_esr_version(self):
|
||||
self._test('/firefox/organizations/system-requirements/',
|
||||
'/firefox/24.0/system-requirements/')
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
# 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.http import Http404
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from funfactory.urlresolvers import reverse
|
||||
from mock import patch, Mock
|
||||
from nose.tools import eq_, ok_
|
||||
from rna.models import Release
|
||||
from nose.tools import ok_
|
||||
|
||||
from bedrock.firefox import views
|
||||
from bedrock.mozorg.tests import TestCase
|
||||
|
||||
|
||||
|
@ -25,190 +18,3 @@ class TestFirefoxNew(TestCase):
|
|||
resp = self.client.get(reverse('firefox.new'))
|
||||
|
||||
ok_('x-frame-options' not in resp)
|
||||
|
||||
|
||||
class TestRNAViews(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
self.request = self.factory.get('/')
|
||||
|
||||
self.render_patch = patch('bedrock.firefox.views.l10n_utils.render')
|
||||
self.mock_render = self.render_patch.start()
|
||||
self.mock_render.return_value.has_header.return_value = False
|
||||
|
||||
def tearDown(self):
|
||||
self.render_patch.stop()
|
||||
|
||||
@property
|
||||
def last_ctx(self):
|
||||
"""
|
||||
Convenient way to access the context of the last rendered
|
||||
response.
|
||||
"""
|
||||
return self.mock_render.call_args[0][2]
|
||||
|
||||
@patch('bedrock.firefox.views.get_object_or_404')
|
||||
@patch('bedrock.firefox.views.Q')
|
||||
def test_get_release_or_404(self, Q, get_object_or_404):
|
||||
eq_(views.get_release_or_404('version', 'product'),
|
||||
get_object_or_404.return_value)
|
||||
get_object_or_404.assert_called_with(
|
||||
Release, Q.return_value, version='version')
|
||||
Q.assert_called_with(product='product')
|
||||
|
||||
@patch('bedrock.firefox.views.get_object_or_404')
|
||||
@patch('bedrock.firefox.views.Q')
|
||||
def test_get_release_or_404_esr(self, Q, get_object_or_404):
|
||||
eq_(views.get_release_or_404('24.5.0', 'Firefox'),
|
||||
get_object_or_404.return_value)
|
||||
Q.assert_any_call(product='Firefox')
|
||||
Q.assert_any_call(product='Firefox Extended Support Release')
|
||||
Q.__or__.assert_called()
|
||||
|
||||
@override_settings(DEV=False)
|
||||
@patch('bedrock.firefox.views.release_notes_template')
|
||||
@patch('bedrock.firefox.views.get_release_or_404')
|
||||
@patch('bedrock.firefox.views.equivalent_release_url')
|
||||
def test_release_notes(self, mock_equiv_rel_url, get_release_or_404,
|
||||
mock_release_notes_template):
|
||||
"""
|
||||
Should use release returned from get_release_or_404 with the
|
||||
correct params and pass the correct context variables and
|
||||
template to l10n_utils.render.
|
||||
"""
|
||||
mock_release = get_release_or_404.return_value
|
||||
mock_release.major_version.return_value = '34'
|
||||
mock_release.notes.return_value = ([Release(id=1), Release(id=2)],
|
||||
[Release(id=3), Release(id=4)])
|
||||
|
||||
views.release_notes(self.request, '27.0')
|
||||
get_release_or_404.assert_called_with('27.0', 'Firefox')
|
||||
mock_release.notes.assert_called_with(public_only=True)
|
||||
eq_(self.last_ctx['version'], '27.0')
|
||||
eq_(self.last_ctx['release'], mock_release)
|
||||
eq_(self.last_ctx['new_features'], [Release(id=1), Release(id=2)])
|
||||
eq_(self.last_ctx['known_issues'], [Release(id=3), Release(id=4)])
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
mock_release_notes_template.return_value)
|
||||
mock_equiv_rel_url.assert_called_with(mock_release)
|
||||
mock_release_notes_template.assert_called_with(
|
||||
mock_release.channel, 'Firefox', 34)
|
||||
|
||||
@patch('bedrock.firefox.views.get_release_or_404')
|
||||
@patch('bedrock.firefox.views.releasenotes_url')
|
||||
def test_release_notes_beta_redirect(self, releasenotes_url,
|
||||
get_release_or_404):
|
||||
"""
|
||||
Should redirect to url for beta release
|
||||
"""
|
||||
get_release_or_404.side_effect = [Http404, 'mock release']
|
||||
releasenotes_url.return_value = '/firefox/27.0beta/releasenotes/'
|
||||
response = views.release_notes(self.request, '27.0')
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['location'], '/firefox/27.0beta/releasenotes/')
|
||||
get_release_or_404.assert_called_with('27.0beta', 'Firefox')
|
||||
releasenotes_url.assert_called_with('mock release')
|
||||
|
||||
@patch('bedrock.firefox.views.get_release_or_404')
|
||||
def test_system_requirements(self, get_release_or_404):
|
||||
"""
|
||||
Should use release returned from get_release_or_404, with a
|
||||
default channel of Release and default product of Firefox,
|
||||
and pass the version to l10n_utils.render
|
||||
"""
|
||||
views.system_requirements(self.request, '27.0.1')
|
||||
get_release_or_404.assert_called_with('27.0.1', 'Firefox')
|
||||
eq_(self.last_ctx['release'], get_release_or_404.return_value)
|
||||
eq_(self.last_ctx['version'], '27.0.1')
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
'firefox/releases/system_requirements.html')
|
||||
|
||||
def test_release_notes_template(self):
|
||||
"""
|
||||
Should return correct template name based on channel
|
||||
and product
|
||||
"""
|
||||
eq_(views.release_notes_template('', 'Firefox OS'),
|
||||
'firefox/releases/os-notes.html')
|
||||
eq_(views.release_notes_template('Nightly', 'Firefox'),
|
||||
'firefox/releases/nightly-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox'),
|
||||
'firefox/releases/aurora-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox', 35),
|
||||
'firefox/releases/dev-browser-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox', 34),
|
||||
'firefox/releases/aurora-notes.html')
|
||||
eq_(views.release_notes_template('Beta', 'Firefox'),
|
||||
'firefox/releases/beta-notes.html')
|
||||
eq_(views.release_notes_template('Release', 'Firefox'),
|
||||
'firefox/releases/release-notes.html')
|
||||
eq_(views.release_notes_template('ESR', 'Firefox'),
|
||||
'firefox/releases/esr-notes.html')
|
||||
eq_(views.release_notes_template('', ''),
|
||||
'firefox/releases/release-notes.html')
|
||||
|
||||
@patch('bedrock.firefox.views.get_release_or_404')
|
||||
def test_firefox_os_manual_template(self, get_release_or_404):
|
||||
"""
|
||||
Should render from pre-RNA template without querying DB
|
||||
"""
|
||||
views.release_notes(self.request, '1.0.1', product='Firefox OS')
|
||||
get_release_or_404.assert_never_called()
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
'firefox/os/notes-1.0.1.html')
|
||||
|
||||
@override_settings(DEV=False)
|
||||
@patch('bedrock.firefox.views.get_object_or_404')
|
||||
def test_non_public_release(self, get_object_or_404):
|
||||
"""
|
||||
Should raise 404 if not release.is_public and not settings.DEV
|
||||
"""
|
||||
get_object_or_404.return_value = Release(is_public=False)
|
||||
with self.assertRaises(Http404):
|
||||
views.get_release_or_404('42', 'Firefox')
|
||||
|
||||
@patch('bedrock.firefox.views.releasenotes_url')
|
||||
def test_no_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return None without calling releasenotes_url
|
||||
"""
|
||||
release = Mock()
|
||||
release.equivalent_android_release.return_value = None
|
||||
release.equivalent_desktop_release.return_value = None
|
||||
eq_(views.equivalent_release_url(release), None)
|
||||
eq_(mock_releasenotes_url.called, 0)
|
||||
|
||||
@patch('bedrock.firefox.views.releasenotes_url')
|
||||
def test_android_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return the url for the equivalent android release
|
||||
"""
|
||||
release = Mock()
|
||||
eq_(views.equivalent_release_url(release),
|
||||
mock_releasenotes_url.return_value)
|
||||
mock_releasenotes_url.assert_called_with(
|
||||
release.equivalent_android_release.return_value)
|
||||
|
||||
@patch('bedrock.firefox.views.releasenotes_url')
|
||||
def test_desktop_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return the url for the equivalent desktop release
|
||||
"""
|
||||
release = Mock()
|
||||
release.equivalent_android_release.return_value = None
|
||||
eq_(views.equivalent_release_url(release),
|
||||
mock_releasenotes_url.return_value)
|
||||
mock_releasenotes_url.assert_called_with(
|
||||
release.equivalent_desktop_release.return_value)
|
||||
|
||||
@patch('bedrock.firefox.views.android_builds')
|
||||
def test_get_download_url_android(self, mock_android_builds):
|
||||
"""
|
||||
Shoud return the download link for the release.channel from
|
||||
android_builds
|
||||
"""
|
||||
mock_android_builds.return_value = [{'download_link': '/download'}]
|
||||
release = Mock(product='Firefox for Android')
|
||||
link = views.get_download_url(release)
|
||||
eq_(link, '/download')
|
||||
mock_android_builds.assert_called_with(release.channel)
|
||||
|
|
|
@ -5,13 +5,15 @@ from django.conf.urls import patterns, url
|
|||
|
||||
from commonware.response.decorators import xframe_allow
|
||||
|
||||
from bedrock.firefox import version_re
|
||||
from bedrock.redirects.util import redirect
|
||||
from bedrock.mozorg.util import page
|
||||
|
||||
import views
|
||||
import bedrock.releasenotes.views
|
||||
from bedrock.releasenotes import version_re
|
||||
|
||||
|
||||
latest_re = r'^firefox(?:/(?P<fx_version>%s))?/%s/$'
|
||||
latest_re = r'^firefox(?:/(?P<version>%s))?/%s/$'
|
||||
firstrun_re = latest_re % (version_re, 'firstrun')
|
||||
whatsnew_re = latest_re % (version_re, 'whatsnew')
|
||||
tour_re = latest_re % (version_re, 'tour')
|
||||
|
@ -36,11 +38,6 @@ urlpatterns = patterns('',
|
|||
page('firefox/developer', 'firefox/developer.html'),
|
||||
page('firefox/geolocation', 'firefox/geolocation.html'),
|
||||
page('firefox/interest-dashboard', 'firefox/interest-dashboard.html'),
|
||||
url('^(?:%s)/(?:%s/)?notes/$' % (product_re, channel_re),
|
||||
views.latest_notes, name='firefox.notes'),
|
||||
url('^firefox/latest/releasenotes/$', views.latest_notes),
|
||||
url('^firefox/(?:%s/)?system-requirements/$' % channel_re,
|
||||
views.latest_sysreq, name='firefox.sysreq'),
|
||||
page('firefox/android', 'firefox/android/index.html'),
|
||||
page('firefox/android/faq', 'firefox/android/faq.html'),
|
||||
page('firefox/os/faq', 'firefox/os/faq.html'),
|
||||
|
@ -53,8 +50,6 @@ urlpatterns = patterns('',
|
|||
page('firefox/organizations/faq', 'firefox/organizations/faq.html'),
|
||||
page('firefox/organizations', 'firefox/organizations/organizations.html'),
|
||||
page('firefox/nightly/firstrun', 'firefox/nightly_firstrun.html'),
|
||||
url('^firefox/releases/$', views.releases_index,
|
||||
name='firefox.releases.index'),
|
||||
url(r'^firefox/installer-help/$', views.installer_help,
|
||||
name='firefox.installer-help'),
|
||||
|
||||
|
@ -77,19 +72,30 @@ urlpatterns = patterns('',
|
|||
page('firefox/os', 'firefox/os/index.html'),
|
||||
page('firefox/os/releases', 'firefox/os/releases.html'),
|
||||
|
||||
# firefox/os/notes/ should redirect to the latest version; update this in /redirects/urls.py
|
||||
url('^firefox/os/notes/(?P<fx_version>%s)/$' % version_re,
|
||||
views.release_notes, {'product': 'Firefox OS'},
|
||||
name='firefox.os.releasenotes'),
|
||||
|
||||
page('mwc', 'firefox/os/mwc-2014-preview.html'),
|
||||
page('firefox/os/devices', 'firefox/os/devices.html'),
|
||||
|
||||
page('firefox/independent', 'firefox/independent.html'),
|
||||
|
||||
url(releasenotes_re, views.release_notes, name='firefox.releasenotes'),
|
||||
url(mobile_releasenotes_re, views.release_notes,
|
||||
|
||||
# Release notes
|
||||
url('^(?:%s)/(?:%s/)?notes/$' % (product_re, channel_re),
|
||||
bedrock.releasenotes.views.latest_notes, name='firefox.notes'),
|
||||
url('firefox/latest/releasenotes/$', bedrock.releasenotes.views.latest_notes,
|
||||
{'product': 'firefox'}),
|
||||
url('^firefox/(?:%s/)?system-requirements/$' % channel_re,
|
||||
bedrock.releasenotes.views.latest_sysreq,
|
||||
{'product': 'firefox'}, name='firefox.sysreq'),
|
||||
url(releasenotes_re, bedrock.releasenotes.views.release_notes, name='firefox.releasenotes'),
|
||||
url(mobile_releasenotes_re, bedrock.releasenotes.views.release_notes,
|
||||
{'product': 'Firefox for Android'}, name='mobile.releasenotes'),
|
||||
url(sysreq_re, views.system_requirements,
|
||||
url(sysreq_re, bedrock.releasenotes.views.system_requirements,
|
||||
name='firefox.system_requirements'),
|
||||
# firefox/os/notes/ should redirect to the latest version; update this in /redirects/urls.py
|
||||
url('^firefox/os/notes/(?P<version>%s)/$' % version_re,
|
||||
bedrock.releasenotes.views.release_notes, {'product': 'Firefox OS'},
|
||||
name='firefox.os.releasenotes'),
|
||||
url('^firefox/releases/$', bedrock.releasenotes.views.releases_index,
|
||||
{'product': 'Firefox'}, name='firefox.releases.index'),
|
||||
)
|
||||
|
|
|
@ -8,10 +8,7 @@ import json
|
|||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.http import (
|
||||
Http404, HttpResponsePermanentRedirect, HttpResponseRedirect)
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import HttpResponsePermanentRedirect, HttpResponseRedirect
|
||||
from django.views.decorators.csrf import csrf_exempt, csrf_protect
|
||||
from django.views.decorators.vary import vary_on_headers
|
||||
from django.views.generic.base import TemplateView
|
||||
|
@ -20,14 +17,10 @@ import basket
|
|||
from funfactory.urlresolvers import reverse
|
||||
from jingo_minify.helpers import BUILD_ID_JS, BUNDLE_HASHES
|
||||
from lib import l10n_utils
|
||||
from rna.models import Release
|
||||
|
||||
from bedrock.firefox import version_re
|
||||
from bedrock.releasenotes import version_re
|
||||
from bedrock.firefox.forms import SMSSendForm
|
||||
from bedrock.mozorg.decorators import cache_control_expires
|
||||
from bedrock.mozorg.views import process_partnership_form
|
||||
from bedrock.mozorg.helpers.misc import releasenotes_url
|
||||
from bedrock.mozorg.helpers.download_buttons import android_builds
|
||||
from bedrock.firefox.firefox_details import firefox_details, mobile_details
|
||||
from lib.l10n_utils.dotlang import _
|
||||
from product_details.version_compare import Version
|
||||
|
@ -102,12 +95,6 @@ INSTALLER_CHANNElS = [
|
|||
# 'nightly', # soon
|
||||
]
|
||||
|
||||
SUPPORT_URLS = {
|
||||
'Firefox for Android': 'https://support.mozilla.org/products/mobile',
|
||||
'Firefox OS': 'https://support.mozilla.org/products/firefox-os',
|
||||
'Firefox': 'https://support.mozilla.org/products/firefox'
|
||||
}
|
||||
|
||||
|
||||
def get_js_bundle_files(bundle):
|
||||
"""
|
||||
|
@ -260,62 +247,6 @@ def firefox_partners(request):
|
|||
request, 'firefox/partners/index.html', 'firefox.partners.index', template_vars, form_kwargs)
|
||||
|
||||
|
||||
def releases_index(request):
|
||||
releases = {}
|
||||
major_releases = firefox_details.firefox_history_major_releases
|
||||
minor_releases = firefox_details.firefox_history_stability_releases
|
||||
|
||||
for release in major_releases:
|
||||
major_verion = float(re.findall(r'^\d+\.\d+', release)[0])
|
||||
# The version numbering scheme of Firefox changes sometimes. The second
|
||||
# number has not been used since Firefox 4, then reintroduced with
|
||||
# Firefox ESR 24 (Bug 870540). On this index page, 24.1.x should be
|
||||
# fallen under 24.0. This patter is a tricky part.
|
||||
major_pattern = r'^' + \
|
||||
re.escape(
|
||||
('%s' if major_verion < 4 else '%g') % round(major_verion, 1))
|
||||
releases[major_verion] = {
|
||||
'major': release,
|
||||
'minor': sorted(filter(lambda x: re.findall(major_pattern, x),
|
||||
minor_releases),
|
||||
key=lambda x: int(re.findall(r'\d+$', x)[0]))
|
||||
}
|
||||
|
||||
return l10n_utils.render(request, 'firefox/releases/index.html',
|
||||
{'releases': sorted(releases.items(), reverse=True)})
|
||||
|
||||
|
||||
def latest_notes(request, product='firefox', channel='release'):
|
||||
version = get_latest_version(product, channel)
|
||||
|
||||
if channel == 'beta':
|
||||
version = re.sub(r'b\d+$', 'beta', version)
|
||||
if channel == 'organizations':
|
||||
version = re.sub(r'esr$', '', version)
|
||||
|
||||
dir = 'auroranotes' if channel == 'aurora' else 'releasenotes'
|
||||
path = [product, version, dir]
|
||||
locale = getattr(request, 'locale', None)
|
||||
if locale:
|
||||
path.insert(0, locale)
|
||||
return HttpResponseRedirect('/' + '/'.join(path) + '/')
|
||||
|
||||
|
||||
def latest_sysreq(request, channel='release'):
|
||||
version = get_latest_version('firefox', channel)
|
||||
|
||||
if channel == 'beta':
|
||||
version = re.sub(r'b\d+$', 'beta', version)
|
||||
if channel == 'organizations':
|
||||
version = re.sub(r'^(\d+).+', r'\1.0', version)
|
||||
|
||||
path = ['firefox', version, 'system-requirements']
|
||||
locale = getattr(request, 'locale', None)
|
||||
if locale:
|
||||
path.insert(0, locale)
|
||||
return HttpResponseRedirect('/' + '/'.join(path) + '/')
|
||||
|
||||
|
||||
def show_devbrowser_firstrun(version):
|
||||
match = re.match(r'\d{1,2}', version)
|
||||
if match:
|
||||
|
@ -401,7 +332,7 @@ class FirstrunView(LatestFxView):
|
|||
return super(FirstrunView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_template_names(self):
|
||||
version = self.kwargs.get('fx_version') or ''
|
||||
version = self.kwargs.get('version') or ''
|
||||
|
||||
if show_devbrowser_firstrun(version):
|
||||
template = 'firefox/dev-firstrun.html'
|
||||
|
@ -448,7 +379,7 @@ class WhatsnewView(LatestFxView):
|
|||
return ctx
|
||||
|
||||
def get_template_names(self):
|
||||
version = self.kwargs.get('fx_version') or ''
|
||||
version = self.kwargs.get('version') or ''
|
||||
locale = l10n_utils.get_locale(self.request)
|
||||
oldversion = self.request.GET.get('oldversion', '')
|
||||
# old versions of Firefox sent a prefixed version
|
||||
|
@ -487,7 +418,7 @@ class TourView(LatestFxView):
|
|||
return super(TourView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_template_names(self):
|
||||
version = self.kwargs.get('fx_version') or ''
|
||||
version = self.kwargs.get('version') or ''
|
||||
|
||||
if show_devbrowser_firstrun(version):
|
||||
template = 'firefox/dev-firstrun.html'
|
||||
|
@ -496,77 +427,3 @@ class TourView(LatestFxView):
|
|||
|
||||
# return a list to conform with original intention
|
||||
return [template]
|
||||
|
||||
|
||||
def release_notes_template(channel, product, version=None):
|
||||
if product == 'Firefox OS':
|
||||
return 'firefox/releases/os-notes.html'
|
||||
prefix = dict((c, c.lower()) for c in Release.CHANNELS)
|
||||
if product == 'Firefox' and channel == 'Aurora' and version >= 35:
|
||||
return 'firefox/releases/dev-browser-notes.html'
|
||||
return 'firefox/releases/%s-notes.html' % prefix.get(channel, 'release')
|
||||
|
||||
|
||||
def equivalent_release_url(release):
|
||||
equivalent_release = (release.equivalent_android_release() or
|
||||
release.equivalent_desktop_release())
|
||||
if equivalent_release:
|
||||
return releasenotes_url(equivalent_release)
|
||||
|
||||
|
||||
def get_release_or_404(version, product):
|
||||
if product == 'Firefox' and len(version.split('.')) == 3:
|
||||
product_query = Q(product='Firefox') | Q(
|
||||
product='Firefox Extended Support Release')
|
||||
else:
|
||||
product_query = Q(product=product)
|
||||
release = get_object_or_404(Release, product_query, version=version)
|
||||
if not release.is_public and not settings.DEV:
|
||||
raise Http404
|
||||
return release
|
||||
|
||||
|
||||
def get_download_url(release):
|
||||
if release.product == 'Firefox for Android':
|
||||
return android_builds(release.channel)[0]['download_link']
|
||||
else:
|
||||
if release.channel == 'Aurora':
|
||||
return reverse('firefox.channel') + '#aurora'
|
||||
elif release.channel == 'Beta':
|
||||
return reverse('firefox.channel') + '#beta'
|
||||
else:
|
||||
return reverse('firefox')
|
||||
|
||||
|
||||
@cache_control_expires(1)
|
||||
def release_notes(request, fx_version, product='Firefox'):
|
||||
if product == 'Firefox OS' and fx_version in ('1.0.1', '1.1', '1.2'):
|
||||
return l10n_utils.render(
|
||||
request, 'firefox/os/notes-%s.html' % fx_version)
|
||||
|
||||
try:
|
||||
release = get_release_or_404(fx_version, product)
|
||||
except Http404:
|
||||
release = get_release_or_404(fx_version + 'beta', product)
|
||||
return HttpResponseRedirect(releasenotes_url(release))
|
||||
|
||||
new_features, known_issues = release.notes(public_only=not settings.DEV)
|
||||
|
||||
return l10n_utils.render(
|
||||
request, release_notes_template(release.channel, product,
|
||||
int(release.major_version())), {
|
||||
'version': fx_version,
|
||||
'download_url': get_download_url(release),
|
||||
'support_url': SUPPORT_URLS.get(product, 'https://support.mozilla.org/'),
|
||||
'release': release,
|
||||
'equivalent_release_url': equivalent_release_url(release),
|
||||
'new_features': new_features,
|
||||
'known_issues': known_issues})
|
||||
|
||||
|
||||
@cache_control_expires(1)
|
||||
def system_requirements(request, fx_version, product='Firefox'):
|
||||
release = get_release_or_404(fx_version, product)
|
||||
return l10n_utils.render(
|
||||
request, 'firefox/releases/system_requirements.html',
|
||||
{'release': release, 'version': fx_version})
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# 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/.
|
||||
|
||||
# Adapted from django-mozilla-product-details
|
||||
version_re = (r"\d+" # major (x in x.y)
|
||||
"\.\d+" # minor1 (y in x.y)
|
||||
"\.?(?:\d+)?" # minor2 (z in x.y.z)
|
||||
"\.?(?:\d+)?" # minor3 (w in x.y.z.w)
|
||||
"(?:a|b(?:eta)?)?" # alpha/beta
|
||||
"(?:\d*)" # alpha/beta version
|
||||
"(?:pre)?" # pre release
|
||||
"(?:\d)?") # pre release version
|
|
@ -0,0 +1,338 @@
|
|||
# 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.http import Http404
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from funfactory.urlresolvers import reverse
|
||||
from mock import patch, Mock
|
||||
from nose.tools import eq_
|
||||
from rna.models import Release
|
||||
from pyquery import PyQuery as pq
|
||||
|
||||
from bedrock.mozorg.tests import TestCase
|
||||
from bedrock.releasenotes import views
|
||||
from bedrock.firefox.utils import product_details
|
||||
|
||||
|
||||
class TestRNAViews(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
self.request = self.factory.get('/')
|
||||
|
||||
self.render_patch = patch('bedrock.releasenotes.views.l10n_utils.render')
|
||||
self.mock_render = self.render_patch.start()
|
||||
self.mock_render.return_value.has_header.return_value = False
|
||||
|
||||
def tearDown(self):
|
||||
self.render_patch.stop()
|
||||
|
||||
@property
|
||||
def last_ctx(self):
|
||||
"""
|
||||
Convenient way to access the context of the last rendered
|
||||
response.
|
||||
"""
|
||||
return self.mock_render.call_args[0][2]
|
||||
|
||||
@patch('bedrock.releasenotes.views.get_object_or_404')
|
||||
@patch('bedrock.releasenotes.views.Q')
|
||||
def test_get_release_or_404(self, Q, get_object_or_404):
|
||||
eq_(views.get_release_or_404('version', 'product'),
|
||||
get_object_or_404.return_value)
|
||||
get_object_or_404.assert_called_with(
|
||||
Release, Q.return_value, version='version')
|
||||
Q.assert_called_with(product='product')
|
||||
|
||||
@patch('bedrock.releasenotes.views.get_object_or_404')
|
||||
@patch('bedrock.releasenotes.views.Q')
|
||||
def test_get_release_or_404_esr(self, Q, get_object_or_404):
|
||||
eq_(views.get_release_or_404('24.5.0', 'Firefox'),
|
||||
get_object_or_404.return_value)
|
||||
Q.assert_any_call(product='Firefox')
|
||||
Q.assert_any_call(product='Firefox Extended Support Release')
|
||||
Q.__or__.assert_called()
|
||||
|
||||
@override_settings(DEV=False)
|
||||
@patch('bedrock.releasenotes.views.get_release_or_404')
|
||||
@patch('bedrock.releasenotes.views.equivalent_release_url')
|
||||
def test_release_notes(self, mock_equiv_rel_url, get_release_or_404):
|
||||
"""
|
||||
Should use release returned from get_release_or_404 with the
|
||||
correct params and pass the correct context variables and
|
||||
template to l10n_utils.render.
|
||||
"""
|
||||
mock_release = get_release_or_404.return_value
|
||||
mock_release.notes.return_value = ([Release(id=1), Release(id=2)],
|
||||
[Release(id=3), Release(id=4)])
|
||||
|
||||
views.release_notes(self.request, '27.0')
|
||||
get_release_or_404.assert_called_with('27.0', 'Firefox')
|
||||
mock_release.notes.assert_called_with(public_only=True)
|
||||
eq_(self.last_ctx['version'], '27.0')
|
||||
eq_(self.last_ctx['release'], mock_release)
|
||||
eq_(self.last_ctx['new_features'], [Release(id=1), Release(id=2)])
|
||||
eq_(self.last_ctx['known_issues'], [Release(id=3), Release(id=4)])
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
'firefox/releases/release-notes.html')
|
||||
mock_equiv_rel_url.assert_called_with(mock_release)
|
||||
|
||||
@patch('bedrock.releasenotes.views.get_release_or_404')
|
||||
@patch('bedrock.releasenotes.views.releasenotes_url')
|
||||
def test_release_notes_beta_redirect(self, releasenotes_url,
|
||||
get_release_or_404):
|
||||
"""
|
||||
Should redirect to url for beta release
|
||||
"""
|
||||
get_release_or_404.side_effect = [Http404, 'mock release']
|
||||
releasenotes_url.return_value = '/firefox/27.0beta/releasenotes/'
|
||||
response = views.release_notes(self.request, '27.0')
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['location'], '/firefox/27.0beta/releasenotes/')
|
||||
get_release_or_404.assert_called_with('27.0beta', 'Firefox')
|
||||
releasenotes_url.assert_called_with('mock release')
|
||||
|
||||
@patch('bedrock.releasenotes.views.get_release_or_404')
|
||||
def test_system_requirements(self, get_release_or_404):
|
||||
"""
|
||||
Should use release returned from get_release_or_404, with a
|
||||
default channel of Release and default product of Firefox,
|
||||
and pass the version to l10n_utils.render
|
||||
"""
|
||||
views.system_requirements(self.request, '27.0.1')
|
||||
get_release_or_404.assert_called_with('27.0.1', 'Firefox')
|
||||
eq_(self.last_ctx['release'], get_release_or_404.return_value)
|
||||
eq_(self.last_ctx['version'], '27.0.1')
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
'firefox/releases/system_requirements.html')
|
||||
|
||||
def test_release_notes_template(self):
|
||||
"""
|
||||
Should return correct template name based on channel
|
||||
and product
|
||||
"""
|
||||
eq_(views.release_notes_template('', 'Firefox OS'),
|
||||
'firefox/releases/os-notes.html')
|
||||
eq_(views.release_notes_template('Nightly', 'Firefox'),
|
||||
'firefox/releases/nightly-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox'),
|
||||
'firefox/releases/aurora-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox', 35),
|
||||
'firefox/releases/dev-browser-notes.html')
|
||||
eq_(views.release_notes_template('Aurora', 'Firefox', 34),
|
||||
'firefox/releases/aurora-notes.html')
|
||||
eq_(views.release_notes_template('Beta', 'Firefox'),
|
||||
'firefox/releases/beta-notes.html')
|
||||
eq_(views.release_notes_template('Release', 'Firefox'),
|
||||
'firefox/releases/release-notes.html')
|
||||
eq_(views.release_notes_template('ESR', 'Firefox'),
|
||||
'firefox/releases/esr-notes.html')
|
||||
eq_(views.release_notes_template('Release', 'Thunderbird'),
|
||||
'thunderbird/releases/release-notes.html')
|
||||
eq_(views.release_notes_template('Beta', 'Thunderbird'),
|
||||
'thunderbird/releases/beta-notes.html')
|
||||
eq_(views.release_notes_template('', ''),
|
||||
'firefox/releases/release-notes.html')
|
||||
|
||||
@patch('bedrock.releasenotes.views.get_release_or_404')
|
||||
def test_firefox_os_manual_template(self, get_release_or_404):
|
||||
"""
|
||||
Should render from pre-RNA template without querying DB
|
||||
"""
|
||||
views.release_notes(self.request, '1.0.1', product='Firefox OS')
|
||||
get_release_or_404.assert_never_called()
|
||||
eq_(self.mock_render.call_args[0][1],
|
||||
'firefox/os/notes-1.0.1.html')
|
||||
|
||||
@override_settings(DEV=False)
|
||||
@patch('bedrock.releasenotes.views.get_object_or_404')
|
||||
def test_non_public_release(self, get_object_or_404):
|
||||
"""
|
||||
Should raise 404 if not release.is_public and not settings.DEV
|
||||
"""
|
||||
get_object_or_404.return_value = Release(is_public=False)
|
||||
with self.assertRaises(Http404):
|
||||
views.get_release_or_404('42', 'Firefox')
|
||||
|
||||
@patch('bedrock.releasenotes.views.releasenotes_url')
|
||||
def test_no_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return None without calling releasenotes_url
|
||||
"""
|
||||
release = Mock()
|
||||
release.equivalent_android_release.return_value = None
|
||||
release.equivalent_desktop_release.return_value = None
|
||||
eq_(views.equivalent_release_url(release), None)
|
||||
eq_(mock_releasenotes_url.called, 0)
|
||||
|
||||
@patch('bedrock.releasenotes.views.releasenotes_url')
|
||||
def test_android_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return the url for the equivalent android release
|
||||
"""
|
||||
release = Mock()
|
||||
eq_(views.equivalent_release_url(release),
|
||||
mock_releasenotes_url.return_value)
|
||||
mock_releasenotes_url.assert_called_with(
|
||||
release.equivalent_android_release.return_value)
|
||||
|
||||
@patch('bedrock.releasenotes.views.releasenotes_url')
|
||||
def test_desktop_equivalent_release_url(self, mock_releasenotes_url):
|
||||
"""
|
||||
Should return the url for the equivalent desktop release
|
||||
"""
|
||||
release = Mock()
|
||||
release.equivalent_android_release.return_value = None
|
||||
eq_(views.equivalent_release_url(release),
|
||||
mock_releasenotes_url.return_value)
|
||||
mock_releasenotes_url.assert_called_with(
|
||||
release.equivalent_desktop_release.return_value)
|
||||
|
||||
@patch('bedrock.releasenotes.views.android_builds')
|
||||
def test_get_download_url_android(self, mock_android_builds):
|
||||
"""
|
||||
Shoud return the download link for the release.channel from
|
||||
android_builds
|
||||
"""
|
||||
mock_android_builds.return_value = [{'download_link': '/download'}]
|
||||
release = Mock(product='Firefox for Android')
|
||||
link = views.get_download_url(release)
|
||||
eq_(link, '/download')
|
||||
mock_android_builds.assert_called_with(release.channel)
|
||||
|
||||
def test_get_download_url_thunderbird(self):
|
||||
release = Mock(product='Thunderbird')
|
||||
link = views.get_download_url(release)
|
||||
eq_(link, 'https://www.mozilla.org/thunderbird/')
|
||||
|
||||
|
||||
class TestReleaseNotesIndex(TestCase):
|
||||
def test_relnotes_index_firefox(self):
|
||||
with self.activate('en-US'):
|
||||
response = self.client.get(reverse('firefox.releases.index'))
|
||||
doc = pq(response.content)
|
||||
eq_(len(doc('a[href="0.1.html"]')), 1)
|
||||
eq_(len(doc('a[href="0.10.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.0.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.0.8.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.5.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.5.0.12.html"]')), 1)
|
||||
eq_(len(doc('a[href="../2.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../2.0.0.20/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../3.6/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../3.6.28/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../17.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../17.0.11/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.1.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../24.1.1/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../25.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../25.0.1/releasenotes/"]')), 1)
|
||||
|
||||
def test_relnotes_index_thunderbird(self):
|
||||
with self.activate('en-US'):
|
||||
response = self.client.get(reverse('thunderbird.releases.index'))
|
||||
doc = pq(response.content)
|
||||
eq_(len(doc('a[href="0.1.html"]')), 1)
|
||||
eq_(len(doc('a[href="1.5.0.2.html"]')), 1)
|
||||
eq_(len(doc('a[href="../2.0.0.0/releasenotes/"]')), 1)
|
||||
eq_(len(doc('a[href="../3.0.1/releasenotes/"]')), 1)
|
||||
|
||||
|
||||
class TestNotesRedirects(TestCase):
|
||||
def _test(self, url_from, url_to):
|
||||
with self.activate('en-US'):
|
||||
url = '/en-US' + url_from
|
||||
response = self.client.get(url)
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['Location'], 'http://testserver/en-US' + url_to)
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_VERSION='22.0')
|
||||
def test_desktop_release_version(self):
|
||||
self._test('/firefox/notes/',
|
||||
'/firefox/22.0/releasenotes/')
|
||||
self._test('/firefox/latest/releasenotes/',
|
||||
'/firefox/22.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_DEVEL_VERSION='23.0b1')
|
||||
def test_desktop_beta_version(self):
|
||||
self._test('/firefox/beta/notes/',
|
||||
'/firefox/23.0beta/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_AURORA='24.0a2')
|
||||
def test_desktop_aurora_version(self):
|
||||
self._test('/firefox/aurora/notes/',
|
||||
'/firefox/24.0a2/auroranotes/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_ESR='24.2.0esr')
|
||||
def test_desktop_esr_version(self):
|
||||
self._test('/firefox/organizations/notes/',
|
||||
'/firefox/24.2.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
version='22.0')
|
||||
def test_mobile_release_version(self):
|
||||
self._test('/mobile/notes/',
|
||||
'/mobile/22.0/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
beta_version='23.0b1')
|
||||
def test_mobile_beta_version(self):
|
||||
self._test('/mobile/beta/notes/',
|
||||
'/mobile/23.0beta/releasenotes/')
|
||||
|
||||
@patch.dict(product_details.mobile_details,
|
||||
alpha_version='24.0a2')
|
||||
def test_mobile_aurora_version(self):
|
||||
self._test('/mobile/aurora/notes/',
|
||||
'/mobile/24.0a2/auroranotes/')
|
||||
|
||||
@patch.dict(product_details.thunderbird_versions,
|
||||
LATEST_THUNDERBIRD_VERSION='22.0')
|
||||
def test_thunderbird_release_version(self):
|
||||
self._test('/thunderbird/latest/releasenotes/',
|
||||
'/thunderbird/22.0/releasenotes/')
|
||||
|
||||
|
||||
class TestSysreqRedirect(TestCase):
|
||||
def _test(self, url_from, url_to):
|
||||
with self.activate('en-US'):
|
||||
url = '/en-US' + url_from
|
||||
response = self.client.get(url)
|
||||
eq_(response.status_code, 302)
|
||||
eq_(response['Location'], 'http://testserver/en-US' + url_to)
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_VERSION='22.0')
|
||||
def test_desktop_release_version(self):
|
||||
self._test('/firefox/system-requirements/',
|
||||
'/firefox/22.0/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
LATEST_FIREFOX_DEVEL_VERSION='23.0b1')
|
||||
def test_desktop_beta_version(self):
|
||||
self._test('/firefox/beta/system-requirements/',
|
||||
'/firefox/23.0beta/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_AURORA='24.0a2')
|
||||
def test_desktop_aurora_version(self):
|
||||
self._test('/firefox/aurora/system-requirements/',
|
||||
'/firefox/24.0a2/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.firefox_versions,
|
||||
FIREFOX_ESR='24.2.0esr')
|
||||
def test_desktop_esr_version(self):
|
||||
self._test('/firefox/organizations/system-requirements/',
|
||||
'/firefox/24.0/system-requirements/')
|
||||
|
||||
@patch.dict(product_details.thunderbird_versions,
|
||||
LATEST_THUNDERBIRD_VERSION='22.0')
|
||||
def test_thunderbird_release_version(self):
|
||||
self._test('/thunderbird/latest/system-requirements/',
|
||||
'/thunderbird/22.0/system-requirements/')
|
|
@ -0,0 +1,183 @@
|
|||
# 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/.
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from funfactory.urlresolvers import reverse
|
||||
from lib import l10n_utils
|
||||
from rna.models import Release
|
||||
from product_details import product_details
|
||||
|
||||
from bedrock.firefox.firefox_details import firefox_details
|
||||
from bedrock.firefox.views import get_latest_version as firefox_get_latest_version
|
||||
from bedrock.mozorg.decorators import cache_control_expires
|
||||
from bedrock.mozorg.helpers.misc import releasenotes_url
|
||||
from bedrock.mozorg.helpers.download_buttons import android_builds
|
||||
from bedrock.thunderbird.utils import get_latest_version as thunderbird_get_latest_version
|
||||
|
||||
|
||||
SUPPORT_URLS = {
|
||||
'Firefox for Android': 'https://support.mozilla.org/products/mobile',
|
||||
'Firefox OS': 'https://support.mozilla.org/products/firefox-os',
|
||||
'Firefox': 'https://support.mozilla.org/products/firefox',
|
||||
'Thunderbird': 'https://support.mozilla.org/products/thunderbird/',
|
||||
}
|
||||
|
||||
|
||||
def release_notes_template(channel, product, version=None):
|
||||
if product == 'Firefox OS':
|
||||
return 'firefox/releases/os-notes.html'
|
||||
prefix = dict((c, c.lower()) for c in Release.CHANNELS)
|
||||
|
||||
if product == 'Firefox' and channel == 'Aurora' and version >= 35:
|
||||
return 'firefox/releases/dev-browser-notes.html'
|
||||
|
||||
dir = 'firefox'
|
||||
if product == 'Thunderbird':
|
||||
dir = 'thunderbird'
|
||||
|
||||
return ('{dir}/releases/{channel}-notes.html'
|
||||
.format(dir=dir, channel=prefix.get(channel, 'release')))
|
||||
|
||||
|
||||
def equivalent_release_url(release):
|
||||
equivalent_release = (release.equivalent_android_release() or
|
||||
release.equivalent_desktop_release())
|
||||
if equivalent_release:
|
||||
return releasenotes_url(equivalent_release)
|
||||
|
||||
|
||||
def get_release_or_404(version, product):
|
||||
if product == 'Firefox' and len(version.split('.')) == 3:
|
||||
product_query = Q(product='Firefox') | Q(
|
||||
product='Firefox Extended Support Release')
|
||||
else:
|
||||
product_query = Q(product=product)
|
||||
release = get_object_or_404(Release, product_query, version=version)
|
||||
if not release.is_public and not settings.DEV:
|
||||
raise Http404
|
||||
return release
|
||||
|
||||
|
||||
def get_download_url(release):
|
||||
if release.product == 'Thunderbird':
|
||||
return 'https://www.mozilla.org/thunderbird/'
|
||||
elif release.product == 'Firefox for Android':
|
||||
return android_builds(release.channel)[0]['download_link']
|
||||
else:
|
||||
if release.channel == 'Aurora':
|
||||
return reverse('firefox.channel') + '#aurora'
|
||||
elif release.channel == 'Beta':
|
||||
return reverse('firefox.channel') + '#beta'
|
||||
else:
|
||||
return reverse('firefox')
|
||||
|
||||
|
||||
@cache_control_expires(1)
|
||||
def release_notes(request, version, product='Firefox'):
|
||||
if product == 'Firefox OS' and version in ('1.0.1', '1.1', '1.2'):
|
||||
return l10n_utils.render(
|
||||
request, 'firefox/os/notes-%s.html' % version)
|
||||
|
||||
try:
|
||||
release = get_release_or_404(version, product)
|
||||
except Http404:
|
||||
release = get_release_or_404(version + 'beta', product)
|
||||
return HttpResponseRedirect(releasenotes_url(release))
|
||||
|
||||
new_features, known_issues = release.notes(public_only=not settings.DEV)
|
||||
|
||||
return l10n_utils.render(
|
||||
request, release_notes_template(release.channel, product), {
|
||||
'version': version,
|
||||
'download_url': get_download_url(release),
|
||||
'support_url': SUPPORT_URLS.get(product, 'https://support.mozilla.org/'),
|
||||
'release': release,
|
||||
'equivalent_release_url': equivalent_release_url(release),
|
||||
'new_features': new_features,
|
||||
'known_issues': known_issues})
|
||||
|
||||
|
||||
@cache_control_expires(1)
|
||||
def system_requirements(request, version, product='Firefox'):
|
||||
release = get_release_or_404(version, product)
|
||||
dir = 'firefox'
|
||||
if product == 'Thunderbird':
|
||||
dir = 'thunderbird'
|
||||
return l10n_utils.render(
|
||||
request, '{dir}/releases/system_requirements.html'.format(dir=dir),
|
||||
{'release': release, 'version': version})
|
||||
|
||||
|
||||
def latest_notes(request, product='firefox', channel='release'):
|
||||
if product == 'thunderbird':
|
||||
version = thunderbird_get_latest_version(product, channel)
|
||||
else:
|
||||
version = firefox_get_latest_version(product, channel)
|
||||
|
||||
if channel == 'beta':
|
||||
version = re.sub(r'b\d+$', 'beta', version)
|
||||
if channel == 'organizations':
|
||||
version = re.sub(r'esr$', '', version)
|
||||
|
||||
dir = 'auroranotes' if channel == 'aurora' else 'releasenotes'
|
||||
path = [product, version, dir]
|
||||
locale = getattr(request, 'locale', None)
|
||||
if locale:
|
||||
path.insert(0, locale)
|
||||
return HttpResponseRedirect('/' + '/'.join(path) + '/')
|
||||
|
||||
|
||||
def latest_sysreq(request, channel, product):
|
||||
if product == 'thunderbird':
|
||||
version = thunderbird_get_latest_version(product, channel)
|
||||
else:
|
||||
version = firefox_get_latest_version(product, channel)
|
||||
|
||||
if channel == 'beta':
|
||||
version = re.sub(r'b\d+$', 'beta', version)
|
||||
if channel == 'organizations':
|
||||
version = re.sub(r'^(\d+).+', r'\1.0', version)
|
||||
|
||||
dir = 'system-requirements'
|
||||
path = [product, version, dir]
|
||||
locale = getattr(request, 'locale', None)
|
||||
if locale:
|
||||
path.insert(0, locale)
|
||||
return HttpResponseRedirect('/' + '/'.join(path) + '/')
|
||||
|
||||
|
||||
def releases_index(request, product):
|
||||
releases = {}
|
||||
if product == 'Firefox':
|
||||
major_releases = firefox_details.firefox_history_major_releases
|
||||
minor_releases = firefox_details.firefox_history_stability_releases
|
||||
elif product == 'Thunderbird':
|
||||
major_releases = product_details.thunderbird_history_major_releases
|
||||
minor_releases = product_details.thunderbird_history_stability_releases
|
||||
|
||||
for release in major_releases:
|
||||
major_version = float(re.findall(r'^\d+\.\d+', release)[0])
|
||||
# The version numbering scheme of Firefox changes sometimes. The second
|
||||
# number has not been used since Firefox 4, then reintroduced with
|
||||
# Firefox ESR 24 (Bug 870540). On this index page, 24.1.x should be
|
||||
# fallen under 24.0. This patter is a tricky part.
|
||||
major_pattern = r'^' + \
|
||||
re.escape(
|
||||
('%s' if major_version < 4 else '%g') % round(major_version, 1))
|
||||
releases[major_version] = {
|
||||
'major': release,
|
||||
'minor': sorted(filter(lambda x: re.findall(major_pattern, x),
|
||||
minor_releases),
|
||||
key=lambda x: int(re.findall(r'\d+$', x)[0]))
|
||||
}
|
||||
|
||||
return l10n_utils.render(
|
||||
request, '{product}/releases/index.html'.format(product=product.lower()),
|
||||
{'releases': sorted(releases.items(), reverse=True)}
|
||||
)
|
|
@ -982,6 +982,8 @@ INSTALLED_APPS = get_apps(exclude=(
|
|||
'%s.externalfiles' % PROJECT_MODULE,
|
||||
'%s.security' % PROJECT_MODULE,
|
||||
'%s.events' % PROJECT_MODULE,
|
||||
'%s.releasenotes' % PROJECT_MODULE,
|
||||
'%s.thunderbird' % PROJECT_MODULE,
|
||||
|
||||
# libs
|
||||
'django_extensions',
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
{# 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/. -#}
|
||||
|
||||
{% extends "base-resp.html" %}
|
||||
|
||||
{% block body_class %}sky{% endblock %}
|
||||
|
||||
{% block site_css %}
|
||||
{{ css('firefox-resp') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block site_header_nav %}
|
||||
<nav id="nav-main" role="navigation">
|
||||
<span class="toggle" role="button" aria-controls="nav-main-menu" aria-expanded="false" tabindex="0">{{_('Menu')}}</span>
|
||||
<ul id="nav-main-menu" class="has-submenus">
|
||||
<li class="first" id="nav-main-features"><a href="/thunderbird/" tabindex="0" aria-owns="nav-main-features-submenu" aria-haspopup="true">{{_('Thunderbird')}}</a>
|
||||
<ul aria-expanded="false" id="nav-main-features-submenu" class="submenu">
|
||||
<li class="first">
|
||||
<a href="/thunderbird/channel/" tabindex="-1">
|
||||
{{_('Releases')}}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/thunderbird/features/" tabindex="-1">
|
||||
{{_('Features')}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="last">
|
||||
<a href="/thunderbird/organizations/" tabindex="-1">
|
||||
{{_('Thunderbird for Organizations')}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="nav-main-addons">
|
||||
<a href="https://addons.mozilla.org/" tabindex="0" aria-owns="nav-main-addons-submenu" aria-haspopup="true">
|
||||
{{_('Add-ons')}}
|
||||
</a>
|
||||
<ul aria-expanded="false" id="nav-main-addons-submenu" class="submenu">
|
||||
<li class="first">
|
||||
<a href="https://addons.mozilla.org/thunderbird/extensions/" tabindex="-1">
|
||||
{{_('Add-ons')}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="last">
|
||||
<a href="https://addons.mozilla.org/thunderbird/themes/" tabindex="-1">
|
||||
{{_('Themes')}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="last" id="nav-main-support">
|
||||
<a href="https://support.mozilla.org/products/thunderbird/" tabindex="0"
|
||||
aria-owns="nav-main-addons-submenu" aria-haspopup="true">
|
||||
{{_('Support')}}
|
||||
</a>
|
||||
<ul aria-expanded="false" id="nav-main-addons-submenu" class="submenu">
|
||||
<li class="first last">
|
||||
<a href="https://support.mozilla.org/products/thunderbird" tabindex="-1">
|
||||
{{_('Thunderbird Support')}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block email_form %}
|
||||
{% endblock email_form %}
|
||||
|
||||
{% block site_header_logo %}
|
||||
<h2>
|
||||
<a href="/thunderbird/">
|
||||
<img src="{{ media('img/thunderbird/template/thunderbird.png?2014-10') }}"
|
||||
alt="Mozilla Thunderbird"
|
||||
height="70"
|
||||
width="260">
|
||||
</a>
|
||||
</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block site_js %}
|
||||
{{ js('firefox-resp') }}
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
{# 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/. #}
|
||||
|
||||
{% extends "thunderbird/releases/release-notes.html" %}
|
||||
|
||||
{% set channel_name = 'Beta' %}
|
|
@ -0,0 +1,72 @@
|
|||
{# 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/. #}
|
||||
|
||||
{% extends "thunderbird/base-resp.html" %}
|
||||
|
||||
{% block page_title %}{{ _('Mozilla Thunderbird Release Notes') }}{% endblock %}
|
||||
{% block page_desc %}{{ _('Release notes for each version of Thunderbird.') }}{% endblock %}
|
||||
{% block body_id %}thunderbird-releases-index{% endblock %}
|
||||
|
||||
{% block site_css %}
|
||||
{{ css('firefox_releases_index') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<nav class="breadcrumbs">
|
||||
<a href="{{ url('mozorg.home') }}">{{ _('Home') }}</a> >
|
||||
<a href="/thunderbird/">{{ _('Thunderbird') }}</a> >
|
||||
<span>{{ _('Release Notes') }}</span>
|
||||
</nav>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main-feature">
|
||||
<h1>{{ _('Thunderbird Releases') }}</h1>
|
||||
<p>{{ _('Thunderbird release notes are specific to each version of the application. Select your version from the list below to see the release notes for it.') }}</p>
|
||||
</div>
|
||||
|
||||
<div id="main-content">
|
||||
<ol reversed>
|
||||
{% for int_version, versions in releases -%}
|
||||
<li>
|
||||
<strong>{{ get_link(int_version, versions.major) }}</strong>
|
||||
{% if versions.minor -%}
|
||||
<ol>
|
||||
{% for version in versions.minor -%}
|
||||
<li>{{ get_link(int_version, version) }}</li>
|
||||
{% endfor -%}
|
||||
</ol>
|
||||
{% endif -%}
|
||||
</li>
|
||||
{% endfor -%}
|
||||
<li>
|
||||
<strong><a href="0.1.html">0.1</a></strong>
|
||||
<ol>
|
||||
<li><a href="0.2.html">0.2</a></li>
|
||||
<li><a href="0.3.html">0.3</a></li>
|
||||
<li><a href="0.4.html">0.4</a></li>
|
||||
<li><a href="0.5.html">0.5</a></li>
|
||||
<li><a href="0.6.html">0.6</a></li>
|
||||
<li><a href="0.7.html">0.7</a></li>
|
||||
<li><a href="0.8.html">0.8</a></li>
|
||||
<li><a href="0.9.html">0.9</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro get_link(int_version, version) %}
|
||||
{%- if int_version < 2 -%}
|
||||
<a href="{{ version }}.html">{{ version }}</a>
|
||||
{%- elif version == '2.0' -%}
|
||||
<a href="../2.0.0.0/releasenotes/">{{ version }}</a>
|
||||
{%- elif version == '17.0.9' -%}
|
||||
<a href="../17.0.9esr/releasenotes/">{{ version }}</a>
|
||||
{%- elif version == '17.0.10' -%}
|
||||
<a href="../17.0.10esr/releasenotes/">{{ version }}</a>
|
||||
{%- else -%}
|
||||
<a href="../{{ version }}/releasenotes/">{{ version }}</a>
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
|
@ -0,0 +1,161 @@
|
|||
{# 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/. #}
|
||||
|
||||
{% extends "thunderbird/base-resp.html" %}
|
||||
|
||||
{% block page_title_prefix %}{% endblock %}
|
||||
{% block page_title %}{{ _('Thunderbird — {channel} Notes ({version})')|f(channel=channel_name, version=release.version) }}{% endblock %}
|
||||
|
||||
{% block body_id %}notes{% endblock %}
|
||||
{% block body_class %}thunderbird-notes sky{% endblock %}
|
||||
|
||||
{% block site_css %}
|
||||
{{ css('firefox_releasenotes') }}
|
||||
{% endblock %}
|
||||
|
||||
{# channel_name is for display purposes where needed. #}
|
||||
{% set channel_name = channel_name|default('') %}
|
||||
|
||||
{% block content %}
|
||||
<main role="main">
|
||||
<article id="main-content">
|
||||
|
||||
{% block notes_header %}
|
||||
<header class="notes-head">
|
||||
<h1>{{ _('Thunderbird {channel} Notes')|f(channel=channel_name) }}</h1>
|
||||
<h2>{{ _('Version {version}, first offered to {channel} channel users on {date}')|f(channel=release.channel, date=release.release_date|l10n_format_date, version=release.version) }}</h2>
|
||||
|
||||
<p>
|
||||
{{ _('Check out "What’s New" and "Known Issues" for this version of Thunderbird below.') }}
|
||||
{% trans feedback='https://support.mozilla.org/questions/new/thunderbird',
|
||||
bugzilla='https://bugzilla.mozilla.org/' %}
|
||||
As always, you’re encouraged to
|
||||
<a href="{{ feedback }}">tell us what you think</a>,
|
||||
or <a href="{{ bugzilla }}">file a bug in Bugzilla</a>.
|
||||
{% endtrans %}
|
||||
{% if release.bug_list %}
|
||||
<form action="https://bugzilla.mozilla.org/buglist.cgi" method="post">
|
||||
<input type="hidden" name="limit" value="0">
|
||||
<input type="hidden" name="bug_id" value="{{ release.bug_list }}">
|
||||
<p>If interested, please see the <button type="submit">complete list of changes</button> in this release.</p>
|
||||
</form>
|
||||
{% else %}
|
||||
If interested, please see the <a href="{{ release.get_bug_search_url() }}">complete list of changes</a> in this release.
|
||||
{% endif %}
|
||||
{{ release.text|markdown|safe }}
|
||||
</p>
|
||||
</header>
|
||||
{% endblock %}
|
||||
|
||||
<div class="main-column">
|
||||
{% if new_features %}
|
||||
<section class="notes-section" id="new-features">
|
||||
<h3>{{ _('What’s New') }}</h3>
|
||||
<ul class="section-items tagged">
|
||||
{% for note in new_features %}
|
||||
<li {% if not note.tag %}class="untagged"{% endif %} id="note-{{ note.id }}">
|
||||
{% if note.tag %}
|
||||
<b class="tag tag-{{ note.tag.lower() }}">{{ note.tag }}</b>
|
||||
{% endif %}
|
||||
{{ note.note|markdown|safe }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if known_issues %}
|
||||
<section class="notes-section" id="known-issues">
|
||||
<h3>{{ _('Known Issues') }}</h3>
|
||||
<ul class="section-items tagged">
|
||||
{% for note in known_issues %}
|
||||
<li id="note-{{ note.id }}">
|
||||
<b class="tag tag-unresolved">{{ _('unresolved') }}</b>
|
||||
{{ note.note|markdown|safe }}
|
||||
{% if note.fixed_in_release %}
|
||||
<p class="note">
|
||||
<a href="{{ releasenotes_url(note.fixed_in_release) }}">
|
||||
{{ _('Resolved in v{version_number}')|f(version_number=note.fixed_in_release.version) }}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% block notes_sidebar %}
|
||||
<aside id="sidebar" class="sidebar">
|
||||
<section id="try">
|
||||
<h3>{{ _('Try Thunderbird %s')|format(channel_name) }}</h3>
|
||||
<ol>
|
||||
<li class="try1">
|
||||
<a href="{{ url('thunderbird.system_requirements', version) }}">
|
||||
{{ _('Check') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="try2">
|
||||
<a href="{{ download_url }}">
|
||||
{{ _('Download') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="try3">
|
||||
<a href="https://support.mozilla.org/kb/Installing%20Thunderbird">
|
||||
{{ _('Install') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="try4">
|
||||
<a href="https://addons.mozilla.org/thunderbird/">
|
||||
{{ _('Customize') }}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section id="get-involved">
|
||||
<h3>{{ _('Want to get involved?') }}</h3>
|
||||
<p>{{ _('Did you know that most of the content in Thunderbird Support was written by volunteers?') }}<br>
|
||||
<a href="{{ url('mozorg.contribute') }}">{{ _('Find out more') }}</a></p>
|
||||
</section>
|
||||
|
||||
<section id="problems">
|
||||
<h3>{{ _('Having Problems?') }}</h3>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="{{ support_url }}">
|
||||
{{ _('Search for answers on the Thunderbird Support page') }}
|
||||
</a>
|
||||
</li>
|
||||
{% if known_issues %}
|
||||
<li>
|
||||
<a href="#known-issues">
|
||||
{{ _('Look at the known issues list and see if we already know about the problem') }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="https://bugzilla.mozilla.org/enter_bug.cgi">
|
||||
{{ _('If you can’t find reference to your issue, please consider filing a technical bug report') }}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section id="other">
|
||||
<h3>{{ _('Other Resources') }}</h3>
|
||||
<p>
|
||||
<a href="https://blog.mozilla.com/thunderbird/">
|
||||
{{ _('The Thunderbird Blog') }}
|
||||
</a>
|
||||
</p>
|
||||
</section>
|
||||
</aside>
|
||||
{% endblock %}
|
||||
|
||||
</article>
|
||||
</main>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}{% endblock %}
|
|
@ -0,0 +1,33 @@
|
|||
{# 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/. #}
|
||||
|
||||
{% extends "thunderbird/base-resp.html" %}
|
||||
|
||||
{% block page_title_prefix %}{% endblock %}
|
||||
{% block page_title %}{{ _('Thunderbird — {version} System Requirements')|f(version=version) }}{% endblock %}
|
||||
|
||||
{% block body_id %}notes{% endblock %}
|
||||
{% block body_class %}thunderbird-notes sky{% endblock %}
|
||||
|
||||
|
||||
{% block site_css %}
|
||||
{{ css('firefox_releasenotes') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<header id="main-feature">
|
||||
<h1>{{ _('Thunderbird {version} System Requirements')|f(version=version) }}</h1>
|
||||
</header>
|
||||
|
||||
<div id="main-content">
|
||||
<article class="main-column">
|
||||
{{ release.system_requirements|markdown|safe }}
|
||||
</article>
|
||||
</div>
|
||||
{% block sidebar %}{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}{% endblock %}
|
|
@ -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.conf.urls import patterns, url
|
||||
|
||||
import bedrock.releasenotes.views
|
||||
from bedrock.releasenotes import version_re
|
||||
|
||||
|
||||
latest_re = r'^thunderbird(?:/(?P<version>%s))?/%s/$'
|
||||
thunderbird_releasenotes_re = latest_re % (version_re, r'releasenotes')
|
||||
sysreq_re = latest_re % (version_re, 'system-requirements')
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url('^thunderbird/releases/$', bedrock.releasenotes.views.releases_index,
|
||||
{'product': 'Thunderbird'}, name='thunderbird.releases.index'),
|
||||
|
||||
url(thunderbird_releasenotes_re, bedrock.releasenotes.views.release_notes,
|
||||
{'product': 'Thunderbird'}, name='thunderbird.releasenotes'),
|
||||
|
||||
url(sysreq_re, bedrock.releasenotes.views.system_requirements,
|
||||
{'product': 'Thunderbird'}, name='thunderbird.system_requirements'),
|
||||
|
||||
url('^thunderbird/latest/system-requirements/$',
|
||||
bedrock.releasenotes.views.latest_sysreq,
|
||||
{'product': 'thunderbird', 'channel': 'release'}, name='thunderbird.sysreq'),
|
||||
|
||||
url('^thunderbird/latest/releasenotes/$',
|
||||
bedrock.releasenotes.views.latest_notes,
|
||||
{'product': 'thunderbird'}),
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 product_details import product_details
|
||||
|
||||
|
||||
def get_latest_version(product='Thunderbird', channel='release'):
|
||||
return product_details.thunderbird_versions.get('LATEST_THUNDERBIRD_VERSION')
|
|
@ -34,6 +34,7 @@ urlpatterns = patterns(
|
|||
(r'^tabzilla/', include('bedrock.tabzilla.urls')),
|
||||
(r'^security/', include('bedrock.security.urls')),
|
||||
(r'', include('bedrock.firefox.urls')),
|
||||
(r'', include('bedrock.thunderbird.urls')),
|
||||
(r'', include('bedrock.mozorg.urls')),
|
||||
(r'', include('bedrock.newsletter.urls')),
|
||||
(r'', include('bedrock.redirects.urls')),
|
||||
|
|
|
@ -566,6 +566,16 @@ RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?(firefox|mobile)/(2[38]\.0(?:\.\d)?
|
|||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?(firefox|mobile)/(29\.0(?:beta|\.\d)?)/releasenotes(/)?$ /b/$1$2/$3/releasenotes$4 [L,PT]
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?(firefox|mobile)/([3-9]\d\.\d(?:a2|beta|\.\d)?)/(aurora|release)notes(/)?$ /b/$1$2/$3/$4notes$5 [L,PT]
|
||||
|
||||
|
||||
|
||||
# bug 1081917, 1029829, 1029838
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?thunderbird/([3-9]\d\.\d(?:a2|beta|\.\d)?)/releasenotes(/)?$ /b/$1thunderbird/$2/releasenotes$3 [L,PT]
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?thunderbird/([3-9]\d\.\d(?:a2|beta|\.\d)?)/system-requirements(/)?$ /b/$1thunderbird/$2/system-requirements$3 [L,PT]
|
||||
RewriteRule ^/thunderbird/releases/(.*)$ http://www-archive.mozilla.org/thunderbird_releasenotes/en-US/thunderbird/releases/$1 [L,R=301]
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)thunderbird/(.*)/releasenotes(.*)$ http://www-archive.mozilla.org/thunderbird_releasenotes/en-US/thunderbird/$2/releasenotes$4 [L,R=301]
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)thunderbird/(.*)/system-requirements(.*)$ http://www-archive.mozilla.org/thunderbird_releasenotes/en-US/thunderbird/$2/system-requirements$4 [L,R=301]
|
||||
|
||||
|
||||
# bug 1001238, 1025056
|
||||
RewriteRule ^/(\w{2,3}(?:-\w{2}(?:-mac)?)?/)?firefox/(24\.[5678]\.\d)/releasenotes(/)?$ /b/$1firefox/$2/releasenotes$3 [L,PT]
|
||||
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 14 KiB |
Загрузка…
Ссылка в новой задаче