Merge lp:~michael.nelson/ubuntu-webcatalog/788210-navigate-distroseries-2 into lp:ubuntu-webcatalog

Proposed by Michael Nelson
Status: Merged
Approved by: Anthony Lenton
Approved revision: 45
Merged at revision: 30
Proposed branch: lp:~michael.nelson/ubuntu-webcatalog/788210-navigate-distroseries-2
Merge into: lp:ubuntu-webcatalog
Diff against target: 601 lines (+316/-171)
8 files modified
src/webcatalog/models/applications.py (+4/-0)
src/webcatalog/templates/webcatalog/install_options_snippet.html (+13/-9)
src/webcatalog/templatetags/webcatalog.py (+66/-39)
src/webcatalog/tests/__init__.py (+3/-2)
src/webcatalog/tests/test_templatetags.py (+150/-0)
src/webcatalog/tests/test_views.py (+17/-73)
src/webcatalog/utilities.py (+58/-1)
src/webcatalog/views.py (+5/-47)
To merge this branch: bzr merge lp:~michael.nelson/ubuntu-webcatalog/788210-navigate-distroseries-2
Reviewer Review Type Date Requested Status
Anthony Lenton (community) Approve
Review via email: mp+66326@code.launchpad.net

Commit message

Thin out the view code, moving get_user_os into a more readable/testable UserAgentString utility.

Description of the change

Overview
========
This branch refactors more of the view code out into utility classes (get_user_os) to make things a bit more maintainable, but also modifies the behavior of what we display depending on the information we have in the user agent.

Details
=======

I've added a UserAgentString utility, but not yet added explicit tests for it (it is still tested via the view and templatetag tests in the same way as the code that it replaces was. We will need to do this.

I refactored the install_options template tag - it should be pretty self-explanatory now, although I want to check with achuni/danny about the decision for linux users.

I added tests for the template tag directly, removed the corresponding tests from the view tests while leaving 2 functional tests in the view.

To test: follow the readme to bootstrap then `fab test` or you can do an import and test manually for a package that is available on your own distroseries as well as another (chromium sends correct user agent, firefox sends only linux).

The only remaining work to finish bug 788210 is to simply add a section to the app details page that lists links to the app in other series (when available) in a sidebar.

There are other issues that I noticed that we should either create bugs for or fix immediately:
 * When the /cat/application/foopkg/ url is used without the distroseries, we currently blindly redirect to the distroseries specific url (either from teh user agent or the default) without actually knowing if it exists (ie. it could 404). We should instead find the app with the highest released distroseries version and redirect to it (or a default if one is set and available).
 * I personally think we should update the urls to use distroseries versions (/cat/application/foopkg/11.04/ ) for released series (it's an Ubuntu convention to not use code_names after release).

To post a comment you must log in.
44. By Michael Nelson

RED: The link to the users distroseries version should not be escaped.

45. By Michael Nelson

GREEN: The link to users distroseries is not escaped (but the application name is).

Revision history for this message
Anthony Lenton (elachuni) wrote :

Hi Michael,

+1 to the idea of checking if the app exists at all, and which is the most current distroseries we've got, before blindly redirecting to it.

Hm, and good point about changing codenames for versions too. Let's not worry about these in this branch I'll try to push these two fixes up today in a different branch, together with tests for the UserAgentString utility.

PS: Enjoy your holidays! :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/webcatalog/models/applications.py'
2--- src/webcatalog/models/applications.py 2011-06-29 10:04:35 +0000
3+++ src/webcatalog/models/applications.py 2011-06-29 15:39:52 +0000
4@@ -133,6 +133,10 @@
5 args=[self.distroseries.code_name, self.package_name])})
6 return crumbs
7
8+ @property
9+ def architectures_list(self):
10+ return self.architectures.split(',')
11+
12 class Meta:
13 app_label = 'webcatalog'
14
15
16=== modified file 'src/webcatalog/templates/webcatalog/install_options_snippet.html'
17--- src/webcatalog/templates/webcatalog/install_options_snippet.html 2011-06-29 09:24:48 +0000
18+++ src/webcatalog/templates/webcatalog/install_options_snippet.html 2011-06-29 15:39:52 +0000
19@@ -1,11 +1,15 @@
20-{% if hide_button %}
21-{{ message_text }}
22-{% else %}
23-<a href="apt://{{ application.package_name }}" class="awesome">{{ button_text }} {{ application.name }}</a>
24-{% endif %}
25-{% if links %}
26-{% for text, link in links %}
27- <br><a href="{{link}}" class="awesome">{{ text }}</a>
28-{% endfor %}
29+{% load i18n %}
30+{% if message_text %}
31+ {{ message_text }}
32+{% endif %}{% if display_install_button %}
33+ <a href="apt://{{ application.package_name }}" class="awesome">
34+ {% if application.for_purchase %}
35+ Purchase {{ application.name }}
36+ {% else %}
37+ Install {{ application.name }}
38+ {% endif %}
39+ </a>
40+{% endif %}{% if display_ubuntu_download %}
41+<a href="http://www.ubuntu.com/download" class="awesome">{% trans "Download Ubuntu" %}</a>
42 {% endif %}
43
44
45=== modified file 'src/webcatalog/templatetags/webcatalog.py'
46--- src/webcatalog/templatetags/webcatalog.py 2011-06-29 09:24:48 +0000
47+++ src/webcatalog/templatetags/webcatalog.py 2011-06-29 15:39:52 +0000
48@@ -29,9 +29,12 @@
49
50 from django import template
51 from django.core.urlresolvers import reverse
52+from django.utils.html import escape
53+from django.utils.safestring import mark_safe
54+from django.utils.translation import ugettext as _
55
56 from webcatalog.models import Application
57-from webcatalog.views import get_user_os
58+from webcatalog.utilities import UserAgentString
59
60 register = template.Library()
61
62@@ -39,43 +42,67 @@
63 @register.inclusion_tag('webcatalog/install_options_snippet.html',
64 takes_context=True)
65 def install_options(context, application):
66- app = application
67- os = get_user_os(context['user_agent'])
68- button_text = 'Purchase' if app.for_purchase else 'Install'
69- right_platform = os['is_linux']
70- right_arch = app.architectures.find(os['arch']) > -1
71- right_distro = os['distro'].find(app.distroseries.code_name) > -1
72- perfect_match = (right_platform and right_distro and right_arch)
73- message_text = 'Not available for your version of Ubuntu'
74- links = []
75- if not perfect_match:
76- if not right_platform:
77- message_text = "Not available for your platform"
78- links.append(('Download Ubuntu', 'http://www.ubuntu.com/download'))
79- elif not right_distro and os['distro_is_a_guess']:
80- # see if we have this package for *other* distros
81- apps_found = Application.objects.filter(
82- package_name=application.package_name).exclude(
83- distroseries__code_name=os['distro'])
84- if apps_found:
85- message_text = ('Not running %s?' % os['distro'])
86- for app_found in apps_found:
87- args = [app.distroseries.code_name, app.package_name]
88- url = reverse('wc-package-detail', args=args)
89- text = "%s %s for %s" % (button_text, app.name,
90- app_found.distroseries.code_name)
91- links.append((text, url))
92- elif not right_distro:
93- app_found = Application.objects.filter(
94+ """Evaluate the installation options for the application in context."""
95+ useragent = UserAgentString(context['user_agent'])
96+ template_context = dict(application=application, message_text='',
97+ display_install_button=False, display_ubuntu_download=False)
98+
99+ if useragent.distroseries == application.distroseries.code_name:
100+ # If both the distroseries and architecture matches, install away,
101+ # otherwise if the architecture doesn't match inform the user.
102+ for arch in application.architectures_list:
103+ if useragent.matches_appinstall_arch(arch):
104+ template_context['display_install_button'] = True
105+ return template_context
106+
107+ template_context['message_text'] = _(
108+ "{application_name} is not available for "
109+ "your computer.").format(application_name=application.name)
110+ return template_context
111+
112+ if useragent.distroseries:
113+ # If we know a definitive distroseries but doesn't match the
114+ # application being viewed, we check for the app with the users
115+ # series and recommend it, or if it doesn't exist, say so.
116+ try:
117+ Application.objects.get(
118 package_name=application.package_name,
119- distroseries__code_name=os['distro'])
120- if app_found:
121- args = [app.distroseries.code_name, app.package_name]
122- url = reverse('wc-package-detail', args=args)
123- message_text = ('%s is also available for your version '
124- 'of Ubuntu' % app.name)
125- links.append(("%s for os['distro']" % button_text, url))
126+ distroseries__code_name=useragent.distroseries)
127+ app_in_series_url = reverse(
128+ 'wc-package-detail',
129+ args=[application.package_name, useragent.distroseries])
130+ template_context['message_text'] = _(
131+ '{application_name} is also available for '
132+ '<a href="{app_in_series_url}">your version of '
133+ 'Ubuntu</a>.').format(
134+ application_name=escape(application.name),
135+ app_in_series_url=app_in_series_url)
136+ template_context['message_text'] = mark_safe(
137+ template_context['message_text'])
138+ return template_context
139+ except Application.DoesNotExist:
140+ template_context['message_text'] = _(
141+ '{application_name} is not available for your version '
142+ 'of Ubuntu.').format(application_name=application.name)
143+ return template_context
144
145- return dict(application=application, button_text=button_text,
146- hide_button=not perfect_match, message_text=message_text,
147- links=links)
148+ if useragent.is_linux:
149+ # XXX Michael Nelson 2011-06-28 bug=709125
150+ # Until we know what our staging/production domains will be and have
151+ # ubufox updated similarly to apt.canonical.com as per bug 709125,
152+ # we'll only have the correct user-agent for chromium, so we display
153+ # the install button for all linux browsers until that is resolved.
154+ # For most packages this will not affect ubuntu users at all (as
155+ # they are generally arch any and available across
156+ # distroseries). When the package doesn't exist for the Ubuntu
157+ # users distroseries, they'll simply be told that when software
158+ # center opens up. Non-ubuntu/debian users browsers won't
159+ # understand the apt url.
160+ template_context['display_install_button'] = True
161+ return template_context
162+ else:
163+ template_context['message_text'] = _(
164+ '{application_name} is not available for your operating '
165+ 'system.').format(application_name=application.name)
166+ template_context['display_ubuntu_download'] = True
167+ return template_context
168
169=== modified file 'src/webcatalog/tests/__init__.py'
170--- src/webcatalog/tests/__init__.py 2011-04-13 02:24:17 +0000
171+++ src/webcatalog/tests/__init__.py 2011-06-29 15:39:52 +0000
172@@ -16,8 +16,9 @@
173 # along with this program. If not, see <http://www.gnu.org/licenses/>.
174
175 """Import various view, model and other tests for django's default runner."""
176-from .test_forms import *
177 from .test_commands import *
178-from .test_views import *
179 from .test_department_filters import *
180+from .test_forms import *
181 from .test_models import *
182+from .test_templatetags import *
183+from .test_views import *
184
185=== added file 'src/webcatalog/tests/test_templatetags.py'
186--- src/webcatalog/tests/test_templatetags.py 1970-01-01 00:00:00 +0000
187+++ src/webcatalog/tests/test_templatetags.py 2011-06-29 15:39:52 +0000
188@@ -0,0 +1,150 @@
189+# -*- coding: utf-8 -*-
190+# This file is part of the Ubuntu Web Catalog
191+# Copyright (C) 2011 Canonical Ltd.
192+#
193+# This program is free software: you can redistribute it and/or modify
194+# it under the terms of the GNU Affero General Public License as
195+# published by the Free Software Foundation, either version 3 of the
196+# License, or (at your option) any later version.
197+#
198+# This program is distributed in the hope that it will be useful,
199+# but WITHOUT ANY WARRANTY; without even the implied warranty of
200+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
201+# GNU Affero General Public License for more details.
202+#
203+# You should have received a copy of the GNU Affero General Public License
204+# along with this program. If not, see <http://www.gnu.org/licenses/>.
205+
206+"""Tests for the webcatalog template tags."""
207+
208+from __future__ import (
209+ absolute_import,
210+ with_statement,
211+ )
212+
213+from django.core.urlresolvers import reverse
214+from django.template import Context
215+
216+from webcatalog.templatetags.webcatalog import install_options
217+from webcatalog.tests.factory import TestCaseWithFactory
218+
219+__metaclass__ = type
220+__all__ = [
221+ 'InstallOptionsTestCase',
222+ ]
223+
224+
225+class InstallOptionsTestCase(TestCaseWithFactory):
226+
227+ def setUp(self):
228+ super(InstallOptionsTestCase, self).setUp()
229+ self.natty = self.factory.make_distroseries(code_name='natty',
230+ version='11.04')
231+ self.lucid = self.factory.make_distroseries(code_name='lucid',
232+ version='10.04')
233+
234+ def make_useragent(self, linux=True, arch='x86_64', ubuntu_version=None):
235+ os = 'X11; Linux' if linux else 'Windows NT 5.1'
236+ version_string = ''
237+ if ubuntu_version:
238+ version_string = "Ubuntu/" + ubuntu_version
239+ return "blah {os} {arch}; {version_string} blah".format(
240+ os=os, arch=arch, version_string=version_string)
241+
242+ def test_matching_series_arch(self):
243+ # If the users series and arch match - install.
244+ application = self.factory.make_application(
245+ package_name='pkgfoo', distroseries=self.natty,
246+ arch='amd64')
247+ context = Context(
248+ dict(user_agent=self.make_useragent(
249+ ubuntu_version='11.04', arch='x86_64')))
250+
251+ self.assertEqual(
252+ dict(application=application, display_install_button=True,
253+ message_text='', display_ubuntu_download=False),
254+ install_options(context, application))
255+
256+ def test_matching_series_arch_not_supported(self):
257+ # If the users series matches but arch not supported, we let
258+ # them know.
259+ application = self.factory.make_application(
260+ name="Package Foo", package_name='pkgfoo',
261+ distroseries=self.natty, arch='i686')
262+ context = Context(
263+ dict(user_agent=self.make_useragent(
264+ ubuntu_version='11.04', arch='solaris')))
265+
266+ self.assertEqual(dict(
267+ application=application, display_install_button=False,
268+ message_text='Package Foo is not available for your computer.',
269+ display_ubuntu_download=False),
270+ install_options(context, application))
271+
272+ def test_different_series_with_available(self):
273+ # If the users series is different from the app, but the app is
274+ # available for their series, then we display a link to the app
275+ # for their series.
276+ natty_application = self.factory.make_application(
277+ name="Package Foo", package_name='pkgfoo',
278+ distroseries=self.natty)
279+ lucid_application = self.factory.make_application(
280+ name="Package Foo", package_name='pkgfoo',
281+ distroseries=self.lucid)
282+ context = Context(
283+ dict(user_agent=self.make_useragent(ubuntu_version='10.04')))
284+
285+ lucid_app_url = reverse('wc-package-detail', args=['pkgfoo', 'lucid'])
286+ self.assertEqual(dict(
287+ application=natty_application, display_install_button=False,
288+ message_text='Package Foo is also available for '
289+ '<a href="{lucid_app_url}">your version of Ubuntu'
290+ '</a>.'.format(lucid_app_url=lucid_app_url),
291+ display_ubuntu_download=False),
292+ install_options(context, natty_application))
293+
294+ def test_different_series_without_available(self):
295+ # If the users series is different from the app, and the app is
296+ # available for their series, then we say so.
297+ natty_application = self.factory.make_application(
298+ name="Package Foo", package_name='pkgfoo',
299+ distroseries=self.natty)
300+ context = Context(
301+ dict(user_agent=self.make_useragent(ubuntu_version='10.10')))
302+
303+ self.assertEqual(dict(
304+ application=natty_application, display_install_button=False,
305+ message_text='Package Foo is not available for your version '
306+ 'of Ubuntu.',
307+ display_ubuntu_download=False),
308+ install_options(context, natty_application))
309+
310+ def test_linux_only_displays_install_button(self):
311+ # XXX Michael Nelson 2011-06-28 bug=709125
312+ # If the useragent tells us only Linux, we display the apt link
313+ # because until we have ubufox updated for whatever our
314+ # webcatalog domain will be (see update for apt.ubuntu.com on
315+ # bug 709125) only chromium in natty provides the version in the
316+ # user agent.
317+ application = self.factory.make_application(package_name='pkgfoo')
318+ context = Context(dict(
319+ user_agent=self.make_useragent(ubuntu_version='')))
320+
321+ self.assertEqual(
322+ dict(application=application, display_install_button=True,
323+ message_text='', display_ubuntu_download=False),
324+ install_options(context, application))
325+
326+ def test_non_linux_displays_download_ubuntu(self):
327+ # A non-linux client is provided a link to download ubuntu.
328+ application = self.factory.make_application(
329+ package_name='pkgfoo', name="Package Foo")
330+ context = Context(dict(
331+ user_agent=self.make_useragent(linux=False)))
332+
333+ self.assertEqual(
334+ dict(application=application, display_install_button=False,
335+ message_text='Package Foo is not available for your '
336+ 'operating system.',
337+ display_ubuntu_download=True),
338+ install_options(context, application))
339
340=== modified file 'src/webcatalog/tests/test_views.py'
341--- src/webcatalog/tests/test_views.py 2011-06-29 09:24:48 +0000
342+++ src/webcatalog/tests/test_views.py 2011-06-29 15:39:52 +0000
343@@ -116,79 +116,23 @@
344 self.assertContains(response, 'Purchase %s' % app.name)
345 self.assertNotContains(response, 'Install %s' % app.name)
346
347- def test_button_for_matching_distroseries(self):
348- response, app = self.get_app_and_response(for_purchase=True)
349-
350- self.assertContains(response, 'Purchase %s' % app.name)
351- self.assertNotContains(response, 'Install %s' % app.name)
352-
353- def test_button_for_non_matching_distroseries_but_available(self):
354- series = DistroSeries(code_name='natty', version='11.04')
355- series.save()
356- app2 = self.factory.make_application(package_name='pkgfoo',
357- distroseries=series,
358- arch='x86_64')
359- app2.save()
360- response, app = self.get_app_and_response(code_name='oneric',
361- version='11.10',
362- for_purchase=True,
363- detail_distro='oneric')
364-
365- self.assertContains(response, 'Not running %s?' %
366- settings.DEFAULT_DISTRO)
367- self.assertContains(response, 'Purchase %s for oneric' % app.name)
368- self.assertContains(response, '/cat/applications/oneric/pkgfoo/')
369-
370- @patch('webcatalog.templatetags.webcatalog.get_user_os')
371- def test_button_for_non_matching_distroseries_and_unavailable(self,
372- mock_get_user_os):
373- # patch user agent check so we can have distro is a guess be False
374- # otherwise we'll get the 'Not using natty?' message
375- fake = {'is_linux': True, 'distro': 'natty', 'distro_is_a_guess': False,
376- 'arch': 'x86_64'}
377- mock_get_user_os.return_value = fake
378- response, app = self.get_app_and_response(code_name='oneric',
379- version='11.10',
380- for_purchase=True,
381- detail_distro='oneric')
382-
383- self.assertNotContains(response, 'Purchase %s' % app.name)
384- not_avail_msg = 'Not available for your version of Ubuntu'
385- self.assertContains(response, not_avail_msg)
386-
387- def test_button_for_non_matching_platform(self):
388- response, app = self.get_app_and_response(useragent=WINDOWS_USERAGENT)
389-
390- self.assertNotContains(response, 'Purchase %s' % app.name)
391- self.assertContains(response, 'Not available for your platform')
392- self.assertContains(response, 'http://www.ubuntu.com/download')
393- self.assertContains(response, 'Download Ubuntu')
394-
395- def test_app_detail_with_no_useragent(self):
396- # don't set the useragent
397- response, app = self.get_app_and_response(useragent=None)
398-
399- self.assertNotContains(response, 'Purchase %s' % app.name)
400-
401- def test_button_for_non_guessed_match(self):
402- ua = 'blah X11; Linux Ubuntu/11.04 blah blah'
403- response, app = self.get_app_and_response(useragent=ua,
404- for_purchase=True)
405-
406- self.assertContains(response, 'Purchase %s' % app.name)
407- self.assertNotContains(response, 'Install %s' % app.name)
408- self.assertNotContains(response, 'Not running %s?' %
409- settings.DEFAULT_DISTRO)
410-
411- def test_button_for_non_guessed_non_match(self):
412- ua = 'blah X11; Linux Ubuntu/11.10 blah blah'
413- response, app = self.get_app_and_response(useragent=ua,
414- for_purchase=True)
415-
416- self.assertContains(response, 'Not available for your version of'
417- ' Ubuntu')
418- self.assertNotContains(response, 'Not running %s?' %
419- settings.DEFAULT_DISTRO)
420+ def test_link_to_different_series(self):
421+ # If the users series is different from the app, but the app is
422+ # available for their series, then we display a link to the app
423+ # for their series.
424+ lucid = self.factory.make_distroseries(code_name='lucid',
425+ version='10.04')
426+ lucid_app = self.factory.make_application(package_name='pkgfoo',
427+ distroseries=lucid)
428+
429+ response, app = self.get_app_and_response(name="<a>Escape me",
430+ useragent="blah Ubuntu/10.04 blah")
431+
432+ lucid_app_url = reverse('wc-package-detail', args=['pkgfoo', 'lucid'])
433+ self.assertContains(response,
434+ '&lt;a&gt;Escape me is also available for '
435+ '<a href="{lucid_app_url}">your version of Ubuntu</a>.'.format(
436+ lucid_app_url=lucid_app_url))
437
438
439 class ApplicationDetailNoSeriesTestCase(TestCaseWithFactory):
440
441=== modified file 'src/webcatalog/utilities.py'
442--- src/webcatalog/utilities.py 2011-06-29 11:41:31 +0000
443+++ src/webcatalog/utilities.py 2011-06-29 15:39:52 +0000
444@@ -14,18 +14,21 @@
445 # You should have received a copy of the GNU Affero General Public License
446 # along with this program. If not, see <http://www.gnu.org/licenses/>.
447
448-"""SSO/OAuth authenticator for Piston."""
449+"""Utilities used by various modules of the web catalog."""
450
451
452 from __future__ import absolute_import
453
454 __metaclass__ = type
455 __all__ = [
456+ 'full_claimed_id',
457+ 'UserAgentString',
458 'WebServices',
459 'WebServiceError',
460 ]
461
462 import logging
463+import re
464 import urllib
465 from httplib2 import ServerNotFoundError
466
467@@ -127,3 +130,57 @@
468 def full_claimed_id(consumer_key):
469 return '%s/+id/%s' % (settings.OPENID_SSO_SERVER_URL.strip('/'),
470 consumer_key)
471+
472+
473+class UserAgentString(object):
474+ """A helper object for interrogating a user agent string for info."""
475+ def __init__(self, useragent_string):
476+ self.useragent_string = useragent_string
477+
478+ @property
479+ def is_linux(self):
480+ return self.useragent_string.find('Linux') > -1
481+
482+ @property
483+ def is_ubuntu(self):
484+ return self.useragent_string.find('buntu') > 0
485+
486+ @property
487+ def distroseries(self):
488+ distros = {
489+ '10.04': 'lucid',
490+ '10.10': 'maverick',
491+ '11.04': 'natty',
492+ '11.10': 'oneiric',
493+ }
494+ match = re.search(
495+ "buntu/(?P<version>\d\d\.\d\d)", self.useragent_string)
496+ if match:
497+ version = match.groupdict()['version']
498+ return distros.get(version, None)
499+ return None
500+
501+ @property
502+ def linux_arch(self):
503+ match = re.search('Linux (?P<arch>\w+)', self.useragent_string)
504+ if match:
505+ return match.groupdict()['arch']
506+ return None
507+
508+ def matches_appinstall_arch(self, appinstall_arch_tag):
509+ # An empty appinstall arch tag implies all arches.
510+ if appinstall_arch_tag in ('', 'any', 'all'):
511+ return True
512+
513+ browser_arch = self.linux_arch
514+
515+ if appinstall_arch_tag == 'i386':
516+ return browser_arch in ('i386', 'x86')
517+
518+ if appinstall_arch_tag in ('ia64', 'amd64'):
519+ return browser_arch in ('x86_64', 'i686')
520+
521+ if appinstall_arch_tag == browser_arch:
522+ return True
523+
524+ return False
525
526=== modified file 'src/webcatalog/views.py'
527--- src/webcatalog/views.py 2011-06-29 09:30:53 +0000
528+++ src/webcatalog/views.py 2011-06-29 15:39:52 +0000
529@@ -40,6 +40,7 @@
530 Application,
531 Department,
532 )
533+from webcatalog.utilities import UserAgentString
534
535 __metaclass__ = type
536 __all__ = [
537@@ -109,12 +110,13 @@
538
539
540 def application_detail(request, package_name, distro=None):
541- os = get_user_os(request.META.get('HTTP_USER_AGENT', ''))
542+
543 if distro is None:
544+ useragent = UserAgentString(request.META.get('HTTP_USER_AGENT', ''))
545 # Check for the distroseries in the useragent, if we have it,
546 # redirect there.
547- if not os['distro_is_a_guess'] and os['distro']:
548- distro = os['distro']
549+ if useragent.distroseries:
550+ distro = useragent.distroseries
551 else:
552 distro = settings.DEFAULT_DISTRO
553 return HttpResponseRedirect(
554@@ -127,47 +129,3 @@
555 return render_to_response(
556 'webcatalog/application_detail.html', RequestContext(
557 request, dict(application=app, breadcrumbs=app.crumbs())))
558-
559-
560-def get_user_os(user_agent_string):
561- distros = {
562- '10.04': 'lucid',
563- '10.10': 'maverick',
564- '11.04': 'natty',
565- '11.10': 'oneiric',
566- }
567- os = {
568- 'is_linux': False,
569- 'distro': '',
570- 'arch': '',
571- 'distro_is_a_guess': False,
572- }
573- ua = user_agent_string
574- if not ua:
575- return os
576- os['is_linux'] = ua.find('X11; Linux') > -1
577- if os['is_linux']:
578- os['distro'] = settings.DEFAULT_DISTRO
579- os['distro_is_a_guess'] = True
580- # Some browsers will have a patch that will actually give us the distro
581- if ua.find('buntu') > -1:
582- os['distro_is_a_guess'] = False
583- slash = ua.find('/', ua.find('buntu'))
584- if slash > -1:
585- version = ua[slash + 1: slash + 6]
586- distro = distros[version]
587- if distro:
588- os['distro'] = distro
589- os['distro_is_a_guess'] = False
590- else:
591- os['distro'] = ''
592- os['distro_is_a_guess'] = False
593-
594- is_x86_64 = ua.find('x86_64')
595- is_686 = ua.find('i686')
596- if is_x86_64:
597- os['arch'] = 'x86_64'
598- elif is_686:
599- os['arch'] = 'i686'
600- # TODO: DT Get other architectures
601- return os

Subscribers

People subscribed via source and target branches