Merge lp:~canonical-isd-hackers/ubuntu-webcatalog/useragent_778562 into lp:ubuntu-webcatalog

Proposed by Danny Tamez
Status: Merged
Approved by: Danny Tamez
Approved revision: 26
Merged at revision: 26
Proposed branch: lp:~canonical-isd-hackers/ubuntu-webcatalog/useragent_778562
Merge into: lp:ubuntu-webcatalog
Diff against target: 507 lines (+217/-60)
10 files modified
django_project/config/main.cfg (+1/-0)
src/webcatalog/models.py (+5/-5)
src/webcatalog/schema.py (+1/-0)
src/webcatalog/templates/webcatalog/application_detail.html (+10/-1)
src/webcatalog/templates/webcatalog/application_overview_snippet.html (+1/-1)
src/webcatalog/tests/factory.py (+3/-3)
src/webcatalog/tests/test_models.py (+3/-3)
src/webcatalog/tests/test_views.py (+111/-34)
src/webcatalog/urls.py (+5/-4)
src/webcatalog/views.py (+77/-9)
To merge this branch: bzr merge lp:~canonical-isd-hackers/ubuntu-webcatalog/useragent_778562
Reviewer Review Type Date Requested Status
David Owen (community) Approve
Review via email: mp+65553@code.launchpad.net

Commit message

Enhances the application details page to show more helpful messages based on the useragent of the request.

Description of the change

This branch adds support for the application details page to display more helpful messages. In particular, the useragent in the request is examined to determine the user's OS and distroseries. Based on this information the app details page will display alternative links to other distros or a link to the ubuntu download page if the OS detected is not Linux. At this point there is no way to actually determine the distro the user is running so a default guess is used (which is configured in the settings).

To post a comment you must log in.
Revision history for this message
David Owen (dsowen) wrote :

I really like how you factored the tests!

Approved, with recommendation that Linux fields not be set in get_user_os() when not a Linux browser.

review: Approve
Revision history for this message
ISD Branch Mangler (isd-branches-mangler) wrote :

Attempt to merge into lp:ubuntu-webcatalog failed due to conflicts:

text conflict in src/webcatalog/models.py
text conflict in src/webcatalog/templates/webcatalog/department_overview.html
text conflict in src/webcatalog/templates/webcatalog/search_results.html
text conflict in src/webcatalog/urls.py
text conflict in src/webcatalog/views.py

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Hey Danny! I was just pulling this up to find out why it hadn't landed yet (argh, conflicts), but noticed that you're not grabbing the distroseries from the user-agent when present... just wondering why?

Here's a screenshot showing Ubuntu/11.04 for me with chromium:
http://people.canonical.com/~michaeln/tmp/778562-headers.png

It won't be available in all browsers, but those that are patched by ubuntu should have it.

I really don't think we should be guessing at all, as it could provide a very confusing user experience. Either we know their distroseries and take advantage of that, or we don't and do some baseline functionality.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> Here's a screenshot showing Ubuntu/11.04 for me with chromium:
> http://people.canonical.com/~michaeln/tmp/778562-headers.png
>
> It won't be available in all browsers, but those that are patched by ubuntu
> should have it.

I just found bug 709125 which says that it'll no longer be supported in FF, but that ubufox package can add it for certain websites (as they have done for apt.ubuntu.com.

If we did ask them to also include (eventually) the web catalog, would it be SRUd to older series? Hrm.

26. By Danny Tamez

Merged trunk and resolved conflicts.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'django_project/config/main.cfg'
--- django_project/config/main.cfg 2011-06-23 12:38:12 +0000
+++ django_project/config/main.cfg 2011-06-28 15:06:35 +0000
@@ -93,6 +93,7 @@
93serve_site_media = True93serve_site_media = True
94sca_api_url = https://sc.staging.ubuntu.com/api/2.0/94sca_api_url = https://sc.staging.ubuntu.com/api/2.0/
95disk_apt_cache_location = /tmp/webcat_cache95disk_apt_cache_location = /tmp/webcat_cache
96default_distro = natty
9697
97[google]98[google]
98google_analytics_id = UA-1018242-2499google_analytics_id = UA-1018242-24
99100
=== modified file 'src/webcatalog/models.py'
--- src/webcatalog/models.py 2011-06-23 14:20:52 +0000
+++ src/webcatalog/models.py 2011-06-28 15:06:35 +0000
@@ -62,7 +62,7 @@
62 popcon = models.IntegerField()62 popcon = models.IntegerField()
63 channel = models.CharField(max_length=255, blank=True)63 channel = models.CharField(max_length=255, blank=True)
64 screenshot_url = models.URLField(blank=True,64 screenshot_url = models.URLField(blank=True,
65 help_text="Only use this if it is other than the normal screenshot url.")65 help_text="Only use this if it is other than the normal screenshot url.")
66 mimetype = models.CharField(max_length=2048, blank=True)66 mimetype = models.CharField(max_length=2048, blank=True)
67 architectures = models.CharField(max_length=255, blank=True)67 architectures = models.CharField(max_length=255, blank=True)
68 keywords = models.CharField(max_length=255, blank=True)68 keywords = models.CharField(max_length=255, blank=True)
@@ -73,6 +73,9 @@
73 icon_name = models.CharField(max_length=255, blank=True)73 icon_name = models.CharField(max_length=255, blank=True)
74 icon = models.ImageField(upload_to='icons/%Y/%m', max_length=200,74 icon = models.ImageField(upload_to='icons/%Y/%m', max_length=200,
75 null=True, blank=True)75 null=True, blank=True)
76 for_purchase = models.BooleanField(default=False)
77 archive_id = models.CharField(max_length=64, null=True,
78 db_index=True, blank=True, unique=True)
7679
77 # Other desktop fields used by s-c80 # Other desktop fields used by s-c
78 # x-gnome-fullname81 # x-gnome-fullname
@@ -83,9 +86,6 @@
83 # (using python-apt - as above we'll need access to info from different86 # (using python-apt - as above we'll need access to info from different
84 # series etc.)87 # series etc.)
85 description = models.TextField(blank=True)88 description = models.TextField(blank=True)
86 for_purchase = models.BooleanField(default=False)
87 archive_id = models.CharField(max_length=64, null=True,
88 db_index=True, blank=True, unique=True)
8989
90 def __unicode__(self):90 def __unicode__(self):
91 return u"{0} ({1})".format(self.name, self.package_name)91 return u"{0} ({1})".format(self.name, self.package_name)
@@ -127,7 +127,7 @@
127 else:127 else:
128 crumbs = [{'name': 'Get Software', 'url': reverse('wc-index')}]128 crumbs = [{'name': 'Get Software', 'url': reverse('wc-index')}]
129 crumbs.append({'name': self.name, 'url': reverse('wc-package-detail',129 crumbs.append({'name': self.name, 'url': reverse('wc-package-detail',
130 args=[self.package_name])})130 args=[self.distroseries.code_name, self.package_name])})
131 return crumbs131 return crumbs
132132
133class Department(models.Model):133class Department(models.Model):
134134
=== modified file 'src/webcatalog/schema.py'
--- src/webcatalog/schema.py 2011-06-27 12:07:30 +0000
+++ src/webcatalog/schema.py 2011-06-28 15:06:35 +0000
@@ -47,6 +47,7 @@
47 webcatalog.serve_site_media = BoolConfigOption(default=True)47 webcatalog.serve_site_media = BoolConfigOption(default=True)
48 webcatalog.sca_api_url = StringConfigOption()48 webcatalog.sca_api_url = StringConfigOption()
49 webcatalog.disk_apt_cache_location = StringConfigOption()49 webcatalog.disk_apt_cache_location = StringConfigOption()
50 webcatalog.default_distro = StringConfigOption()
50 webcatalog.page_batch_size = IntConfigOption(default=20)51 webcatalog.page_batch_size = IntConfigOption(default=20)
5152
52 google = ConfigSection()53 google = ConfigSection()
5354
=== modified file 'src/webcatalog/templates/webcatalog/application_detail.html'
--- src/webcatalog/templates/webcatalog/application_detail.html 2011-06-23 14:20:52 +0000
+++ src/webcatalog/templates/webcatalog/application_detail.html 2011-06-28 15:06:35 +0000
@@ -27,7 +27,16 @@
27 <img src="http://screenshots.ubuntu.com/thumbnail-with-version/{{ application.package_name }}/ignored" />27 <img src="http://screenshots.ubuntu.com/thumbnail-with-version/{{ application.package_name }}/ignored" />
28 </div>28 </div>
29 <p>{{ application.description }}</p>29 <p>{{ application.description }}</p>
30 <a href="apt://{{ application.package_name }}" class="awesome">{%if application.for_purchase %}Install{% else %}Download{% endif %} {{ application.name }}</a>30 {% if hide_button %}
31 {{ message_text }}
32 {% else %}
33 <a href="apt://{{ application.package_name }}" class="awesome">{{ button_text }} {{ application.name }}</a>
34 {% endif %}
35 {% if links %}
36 {% for text, link in links %}
37 <br><a href="{{link}}" class="awesome">{{ text }}</a>
38 {% endfor %}
39 {% endif %}
31 </div>40 </div>
32 <div class="license">41 <div class="license">
33 <table>42 <table>
3443
=== modified file 'src/webcatalog/templates/webcatalog/application_overview_snippet.html'
--- src/webcatalog/templates/webcatalog/application_overview_snippet.html 2011-06-23 14:20:52 +0000
+++ src/webcatalog/templates/webcatalog/application_overview_snippet.html 2011-06-28 15:06:35 +0000
@@ -5,7 +5,7 @@
5 <img src="{{ STATIC_URL }}images/noicon_32.png"/>5 <img src="{{ STATIC_URL }}images/noicon_32.png"/>
6 {% endif %}6 {% endif %}
7 <h3>7 <h3>
8 <a href="{% url wc-package-detail app.package_name %}">{{ app.name }}</a>8 <a href="{% url wc-package-detail app.distroseries.code_name app.package_name %}">{{ app.name }}</a>
9 </h3>9 </h3>
10 <p>{{ app.comment }}</p>10 <p>{{ app.comment }}</p>
11</div>11</div>
1212
=== modified file 'src/webcatalog/tests/factory.py'
--- src/webcatalog/tests/factory.py 2011-05-06 09:46:17 +0000
+++ src/webcatalog/tests/factory.py 2011-06-28 15:06:35 +0000
@@ -24,7 +24,7 @@
24import os24import os
25from itertools import count25from itertools import count
2626
27from django.core.files.images import ImageFile27from django.contrib.auth.models import User
28from django.test import TestCase28from django.test import TestCase
2929
30from webcatalog.models import (30from webcatalog.models import (
@@ -76,7 +76,7 @@
7676
77 def make_application(self, package_name=None, name=None,77 def make_application(self, package_name=None, name=None,
78 comment=None, description=None, icon_name='', icon=None,78 comment=None, description=None, icon_name='', icon=None,
79 distroseries=None):79 distroseries=None, arch='i686'):
80 if name is None:80 if name is None:
81 name = self.get_unique_string(prefix='Readable Name')81 name = self.get_unique_string(prefix='Readable Name')
82 if package_name is None:82 if package_name is None:
@@ -91,7 +91,7 @@
91 return Application.objects.create(91 return Application.objects.create(
92 package_name=package_name, name=name, comment=comment,92 package_name=package_name, name=name, comment=comment,
93 description=description, popcon=999, icon=icon,93 description=description, popcon=999, icon=icon,
94 icon_name=icon_name, distroseries=distroseries)94 icon_name=icon_name, distroseries=distroseries, architectures=arch)
9595
96 def make_department(self, name, parent=None):96 def make_department(self, name, parent=None):
97 return Department.objects.create(name=name, parent=parent)97 return Department.objects.create(name=name, parent=parent)
9898
=== modified file 'src/webcatalog/tests/test_models.py'
--- src/webcatalog/tests/test_models.py 2011-06-23 14:49:53 +0000
+++ src/webcatalog/tests/test_models.py 2011-06-28 15:06:35 +0000
@@ -65,7 +65,7 @@
65 self.assertEquals([], list(app.departments.all()))65 self.assertEquals([], list(app.departments.all()))
66 expected = [{'name': 'Get Software', 'url': reverse('wc-index')},66 expected = [{'name': 'Get Software', 'url': reverse('wc-index')},
67 {'name': app.name, 'url': reverse('wc-package-detail',67 {'name': app.name, 'url': reverse('wc-package-detail',
68 args=[app.package_name])}]68 args=[app.distroseries.code_name, app.package_name])}]
6969
70 self.assertEquals(expected, app.crumbs())70 self.assertEquals(expected, app.crumbs())
7171
@@ -78,7 +78,7 @@
78 {'name': dept.name, 'url': reverse('wc-department',78 {'name': dept.name, 'url': reverse('wc-department',
79 args=[dept.id])},79 args=[dept.id])},
80 {'name': app.name, 'url': reverse('wc-package-detail',80 {'name': app.name, 'url': reverse('wc-package-detail',
81 args=[app.package_name])}]81 args=[app.distroseries.code_name, app.package_name])}]
8282
83 self.assertEquals(expected, app.crumbs())83 self.assertEquals(expected, app.crumbs())
8484
@@ -93,7 +93,7 @@
93 {'name': dept.name, 'url': reverse('wc-department',93 {'name': dept.name, 'url': reverse('wc-department',
94 args=[dept.id])},94 args=[dept.id])},
95 {'name': app.name, 'url': reverse('wc-package-detail',95 {'name': app.name, 'url': reverse('wc-package-detail',
96 args=[app.package_name])}]96 args=[app.distroseries.code_name, app.package_name])}]
9797
98 self.assertEquals(expected, app.crumbs())98 self.assertEquals(expected, app.crumbs())
9999
100100
=== modified file 'src/webcatalog/tests/test_views.py'
--- src/webcatalog/tests/test_views.py 2011-06-27 13:39:39 +0000
+++ src/webcatalog/tests/test_views.py 2011-06-28 15:06:35 +0000
@@ -22,8 +22,12 @@
22 with_statement,22 with_statement,
23 )23 )
2424
25from django.conf import settings
25from django.core.urlresolvers import reverse26from django.core.urlresolvers import reverse
2627
28from mock import patch
29
30from webcatalog.models import DistroSeries
27from webcatalog.tests.factory import TestCaseWithFactory31from webcatalog.tests.factory import TestCaseWithFactory
28from webcatalog.tests.helpers import patch_settings32from webcatalog.tests.helpers import patch_settings
2933
@@ -35,23 +39,52 @@
35 ]39 ]
3640
3741
42WINDOWS_USERAGENT = ('Mozilla/5.0 (Windows NT 5.1; rv:2.0) '
43 'Gecko/20100101 Firefox/4.0')
44
45UBUNTU_USERAGENT = ('Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) '
46 'Gecko/20100101 Firefox/4.0.1')
47
48
38class PackageDetailTestCase(TestCaseWithFactory):49class PackageDetailTestCase(TestCaseWithFactory):
3950
51 def get_app_and_response(self, code_name='natty', version='11.04',
52 arch='x86_64', name=None, comment=None,
53 description=None, detail_distro=None,
54 detail_package=None, for_purchase=False,
55 useragent=UBUNTU_USERAGENT):
56 series = DistroSeries(code_name=code_name, version=version)
57 series.save()
58 app = self.factory.make_application(package_name='pkgfoo',
59 distroseries=series, arch=arch,
60 name=name, comment=comment,
61 description=description)
62 if for_purchase:
63 app.for_purchase = True
64 app.save()
65 if not detail_distro:
66 detail_distro = app.distroseries.code_name
67 if not detail_package:
68 detail_package = app.package_name
69
70 url = reverse('wc-package-detail', args=[detail_distro, detail_package])
71
72 if useragent:
73 response = self.client.get(url, HTTP_USER_AGENT=useragent)
74 else:
75 response = self.client.get(url)
76 return response, app
77
40 def test_renders_correct_template(self):78 def test_renders_correct_template(self):
41 self.factory.make_application(package_name='pkgfoo')79 response, app = self.get_app_and_response()
42 url = reverse('wc-package-detail', args=['pkgfoo'])
43
44 response = self.client.get(url)
4580
46 self.assertTemplateUsed(response, 'webcatalog/application_detail.html')81 self.assertTemplateUsed(response, 'webcatalog/application_detail.html')
4782
48 def test_includes_application_details(self):83 def test_includes_application_details(self):
49 # The details of an application are included in the rendered html.84 # The details of an application are included in the rendered html.
50 self.factory.make_application(package_name='pkgfoo', name="My app foo",85 response, app = self.get_app_and_response(name='My app foo',
51 comment="The best app eva.", description="A long description.")86 comment='The best app eva.',
52 url = reverse('wc-package-detail', args=['pkgfoo'])87 description='A long description.')
53
54 response = self.client.get(url)
5588
56 self.assertContains(response, "My app foo")89 self.assertContains(response, "My app foo")
57 self.assertContains(response, "The best app eva.")90 self.assertContains(response, "The best app eva.")
@@ -59,40 +92,83 @@
5992
60 def test_screenshot_thumbnail_url(self):93 def test_screenshot_thumbnail_url(self):
61 # The thumbnail link to screenshots is included.94 # The thumbnail link to screenshots is included.
62 self.factory.make_application(package_name='pkgfoo')95 response, app = self.get_app_and_response()
63 url = reverse('wc-package-detail', args=['pkgfoo'])
64
65 response = self.client.get(url)
6696
67 self.assertContains(97 self.assertContains(
68 response, '<img src="http://screenshots.ubuntu.com/'98 response, '<img src="http://screenshots.ubuntu.com/'
69 'thumbnail-with-version/pkgfoo/ignored"')99 'thumbnail-with-version/pkgfoo/ignored"')
70100
71 def test_link_to_apt_package(self):101 def test_link_to_apt_package(self):
72 self.factory.make_application(package_name='pkgfoo')102 response, app = self.get_app_and_response()
73 url = reverse('wc-package-detail', args=['pkgfoo'])103
74104 self.assertContains(response, '<a href="apt://pkgfoo"')
75 response = self.client.get(url)
76
77 self.assertContains( response, '<a href="apt://pkgfoo"')
78105
79 def test_button_for_non_puchase_app(self):106 def test_button_for_non_puchase_app(self):
80 app = self.factory.make_application(package_name='pkgfoo')107 response, app = self.get_app_and_response()
81 url = reverse('wc-package-detail', args=['pkgfoo'])108
82109 self.assertContains(response, 'Install %s' % app.name)
83 response = self.client.get(url)110 self.assertNotContains(response, 'Purcchase %s' % app.name)
84
85 self.assertContains( response, 'Download %s' % app.name)
86111
87 def test_button_for_for_puchase_app(self):112 def test_button_for_for_puchase_app(self):
88 app = self.factory.make_application(package_name='pkgfoo')113 response, app = self.get_app_and_response(for_purchase=True)
89 app.for_purchase = True114
90 app.save()115 self.assertContains(response, 'Purchase %s' % app.name)
91 url = reverse('wc-package-detail', args=['pkgfoo'])116 self.assertNotContains(response, 'Install %s' % app.name)
92117
93 response = self.client.get(url)118 def test_button_for_matching_distroseries(self):
94119 response, app = self.get_app_and_response(for_purchase=True)
95 self.assertContains( response, 'Install %s' % app.name)120
121 self.assertContains(response, 'Purchase %s' % app.name)
122 self.assertNotContains(response, 'Install %s' % app.name)
123
124 def test_button_for_non_matching_distroseries_but_available(self):
125 series = DistroSeries(code_name='natty', version='11.04')
126 series.save()
127 app2 = self.factory.make_application(package_name='pkgfoo',
128 distroseries=series,
129 arch='x86_64')
130 app2.save()
131 response, app = self.get_app_and_response(code_name='oneric',
132 version='11.10',
133 for_purchase=True,
134 detail_distro='oneric')
135
136 self.assertContains(response, 'Not running %s?' %
137 settings.DEFAULT_DISTRO)
138 self.assertContains(response, 'Purchase %s for oneric' % app.name)
139 self.assertContains(response, '/cat/applications/oneric/pkgfoo/')
140
141 @patch('webcatalog.views.get_user_os')
142 def test_button_for_non_matching_distroseries_and_unavailable(self,
143 mock_get_user_os):
144 # patch user agent check so we can have distro is a guess be False
145 # otherwise we'll get the 'Not using natty?' message
146 fake = {'is_linux': True, 'distro': 'natty', 'distro_is_a_guess': False,
147 'arch': 'x86_64'}
148 mock_get_user_os.return_value = fake
149 response, app = self.get_app_and_response(code_name='oneric',
150 version='11.10',
151 for_purchase=True,
152 detail_distro='oneric')
153
154 self.assertNotContains(response, 'Purchase %s' % app.name)
155 not_avail_msg = 'Not available for your version of Ubuntu'
156 self.assertContains(response, not_avail_msg)
157
158 def test_button_for_non_matching_platform(self):
159 response, app = self.get_app_and_response(useragent=WINDOWS_USERAGENT)
160
161 self.assertNotContains(response, 'Purchase %s' % app.name)
162 self.assertContains(response, 'Not available for your platform')
163 self.assertContains(response, 'http://www.ubuntu.com/download')
164 self.assertContains(response, 'Download Ubuntu')
165
166 def test_app_detail_with_no_useragent(self):
167 # don't set the useragent
168 response, app = self.get_app_and_response(useragent=None)
169
170 self.assertNotContains(response, 'Purchase %s' % app.name)
171
96172
97173
98class SearchTestCase(TestCaseWithFactory):174class SearchTestCase(TestCaseWithFactory):
@@ -201,6 +277,7 @@
201 self.assertEqual(1, page.number)277 self.assertEqual(1, page.number)
202278
203279
280
204class OverviewTestCase(TestCaseWithFactory):281class OverviewTestCase(TestCaseWithFactory):
205 def test_index_contains_links_to_departments(self):282 def test_index_contains_links_to_departments(self):
206 dept = self.factory.make_department('foo')283 dept = self.factory.make_department('foo')
@@ -227,7 +304,7 @@
227 response = self.client.get(reverse('wc-department', args=[dept.id]))304 response = self.client.get(reverse('wc-department', args=[dept.id]))
228305
229 self.assertContains(response, reverse('wc-package-detail',306 self.assertContains(response, reverse('wc-package-detail',
230 args=[app.package_name]))307 args=[app.distroseries.code_name, app.package_name]))
231308
232 def test_department_with_no_subdepts_doesnt_contain_header(self):309 def test_department_with_no_subdepts_doesnt_contain_header(self):
233 dept = self.factory.make_department('bar')310 dept = self.factory.make_department('bar')
234311
=== modified file 'src/webcatalog/urls.py'
--- src/webcatalog/urls.py 2011-06-23 14:20:52 +0000
+++ src/webcatalog/urls.py 2011-06-28 15:06:35 +0000
@@ -22,9 +22,8 @@
22 with_statement,22 with_statement,
23 )23 )
24from django.conf.urls.defaults import patterns, url24from django.conf.urls.defaults import patterns, url
25from django.views.generic.detail import DetailView
2625
27from webcatalog.models import Application26from webcatalog.views import application_detail, application_detail_no_distro
2827
29__metaclass__ = type28__metaclass__ = type
30__all__ = [29__all__ = [
@@ -36,7 +35,9 @@
36 url(r'^$', 'index', name='wc-index'),35 url(r'^$', 'index', name='wc-index'),
37 url(r'^department/(?P<dept_id>\d+)/$', 'department_overview',36 url(r'^department/(?P<dept_id>\d+)/$', 'department_overview',
38 name='wc-department'),37 name='wc-department'),
39 url(r'^applications/(?P<package_name>[-.+\w]+)/$', 'application_detail',38 url(r'^applications/(?P<distro>[-.+\w]+)/(?P<slug>[-.+\w]+)/$',
40 name="wc-package-detail"),39 application_detail, name="wc-package-detail"),
40 url(r'^applications/(?P<slug>[-.+\w]+)/$', application_detail_no_distro,
41 name="wc-package-detail-no-distro"),
41 url(r'^search/$', 'search', name="wc-search"),42 url(r'^search/$', 'search', name="wc-search"),
42)43)
4344
=== modified file 'src/webcatalog/views.py'
--- src/webcatalog/views.py 2011-06-27 14:08:41 +0000
+++ src/webcatalog/views.py 2011-06-28 15:06:35 +0000
@@ -55,6 +55,7 @@
55 return int(page_num)55 return int(page_num)
56 return 156 return 1
5757
58
58def search(request):59def search(request):
59 apps = []60 apps = []
60 query = ''61 query = ''
@@ -82,12 +83,14 @@
82 return render_to_response('webcatalog/search_results.html',83 return render_to_response('webcatalog/search_results.html',
83 context_instance=context)84 context_instance=context)
8485
86
85def index(request):87def index(request):
86 depts = Department.objects.filter(parent=None).order_by('name')88 depts = Department.objects.filter(parent=None).order_by('name')
87 context = RequestContext(request, dict={'depts': depts})89 context = RequestContext(request, dict={'depts': depts})
88 return render_to_response('webcatalog/index.html',90 return render_to_response('webcatalog/index.html',
89 context_instance=context)91 context_instance=context)
9092
93
91def department_overview(request, dept_id):94def department_overview(request, dept_id):
92 dept = get_object_or_404(Department, pk=dept_id)95 dept = get_object_or_404(Department, pk=dept_id)
93 subdepts = Department.objects.filter(parent=dept)96 subdepts = Department.objects.filter(parent=dept)
@@ -104,12 +107,77 @@
104 context_instance=context)107 context_instance=context)
105108
106109
107def application_detail(request, package_name):110def application_detail_no_distro(request, slug):
108 app = get_object_or_404(Application, package_name=package_name)111 default_distro = settings.DEFAULT_DISTRO
109112 return application_detail(request, default_distro, slug)
110 context = RequestContext(request, {113
111 'application': app,114
112 'breadcrumbs': app.crumbs(),115def application_detail(request, distro, slug):
113 })116 os = get_user_os(request)
114 return render_to_response('webcatalog/application_detail.html',117 app = get_object_or_404(Application, package_name=slug,
115 context_instance=context)118 distroseries__code_name=distro)
119 button_text = 'Purchase' if app.for_purchase else 'Install'
120 right_platform = os['is_linux']
121 right_arch = app.architectures.find(os['arch']) > -1
122 right_distro = os['distro'].find(app.distroseries.code_name) > -1
123 perfect_match = (right_platform and right_distro and right_arch)
124 message_text = 'Not available for your version of Ubuntu'
125 links = []
126 if not perfect_match:
127 if not right_platform:
128 message_text = "Not available for your platform"
129 links.append(('Download Ubuntu', 'http://www.ubuntu.com/download'))
130 elif not right_distro and os['distro_is_a_guess']:
131 # see if we have this package for *other* distros
132 apps_found = Application.objects.filter(package_name=slug).exclude(
133 distroseries__code_name=os['distro'])
134 if apps_found:
135 message_text = ('Not running %s?' % os['distro'])
136 for app_found in apps_found:
137 args = [app.distroseries.code_name, app.package_name]
138 url = reverse('wc-package-detail', args=args)
139 text = "%s %s for %s" % (button_text, app.name,
140 app_found.distroseries.code_name)
141 links.append((text, url))
142 elif not right_distro:
143 app_found = Application.objects.filter(package_name=slug,
144 distroseries__code_name=os['distro'])
145 if app_found:
146 args = [app.distroseries.code_name, app.package_name]
147 url = reverse('wc-package-detail', args=args)
148 message_text = ('%s is also available for your version '
149 'of Ubuntu' % app.name)
150 links.append(("%s for os['distro']" % button_text, url))
151
152 ctx = {'application': app, 'button_text': button_text,
153 'hide_button': not perfect_match, 'message_text': message_text,
154 'breadcrumbs': app.crumbs(), 'links': links}
155
156 context = RequestContext(request, dict=ctx)
157 return render_to_response('webcatalog/application_detail.html', context)
158
159
160def get_user_os(request):
161 os = {'is_linux': False, 'distro': 'unknown', 'arch': 'unknown'}
162 try:
163 ua = request.META['HTTP_USER_AGENT']
164 except KeyError:
165 return os
166 os['is_linux'] = ua.find('X11; Linux') > -1
167 # Until we can figure out a way to actually get the distro we'll
168 # assume a default distro
169 if os['is_linux']:
170 os['distro'] = settings.DEFAULT_DISTRO
171 os['distro_is_a_guess'] = True
172 else:
173 os['distro'] = ''
174 os['distro_is_a_guess'] = False
175
176 is_x86_64 = ua.find('x86_64')
177 is_686 = ua.find('i686')
178 if is_x86_64:
179 os['arch'] = 'x86_64'
180 elif is_686:
181 os['arch'] = 'i686'
182 # TODO: DT Get other architectures
183 return os

Subscribers

People subscribed via source and target branches